Quantcast
Channel: SCN : Document List - ABAP Development
Viewing all 935 articles
Browse latest View live

Create Inbound Delivery ( BBP_INB_DELIVERY_CREATE ) Bug

$
0
0

BBP_INB_DELIVERY_CREATE function is used for creating inbound delivery. Normaly created delivery number and error messages are returned, but sometimes function exports empty delivery number, inspite of return table without errors. In this case system actually creates delivery, if you query tables after commit, you will find delivery number.

 

 

Sytem Info that i faced the bug:

SAP ECC 6.0

SAP_ABA7010009SAPKA70109
SAP_BASIS7010009SAPKB70109

 

 

DATA: _header    LIKE  bbp_inbd_l,

        _delivery  LIKE  likp-vbeln,

        _it_detail TYPE STANDARD TABLE OF bbp_inbd_d WITH HEADER LINE,

        _it_return TYPE STANDARD TABLE OF bapireturn WITH HEADER LINE.


  DATA: _vbeln TYPE ekes-vbeln.

 

  SELECT * FROM ekpo WHERE ebeln = 'PO Number'.


    _it_detail-material      = ekpo-matnr.

    _it_detail-matl_desc   = ekpo-txz01.

    _it_detail-deliv_qty     = ekpo-menge.

    _it_detail-unit             = ekpo-meins.

    _it_detail-po_number = ekpo-ebeln.

    _it_detail-po_item      = ekpo-ebelp.

    APPEND _it_detail.

    CLEAR _it_detail.


  ENDSELECT.


  _header-deliv_date = sy-datum.

  _header-deliv_time = sy-uzeit.


  CALL FUNCTION 'BBP_INB_DELIVERY_CREATE'

    EXPORTING

      is_inb_delivery_header = _header

    IMPORTING

      ef_delivery                    = _delivery

    TABLES

      it_inb_delivery_detail = _it_detail[]

      return                         = _it_return[].


  LOOP AT _it_return WHERE type = 'A'

                                          OR type = 'E'

                                          OR type = 'X'.

    EXIT.

  ENDLOOP.

  IF sy-subrc = 0.

    CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.

  ELSE.

    CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'

      EXPORTING

        wait = 'X'.

     IF _delivery IS INITIAL.

         SELECT SINGLE vbeln

         INTO _vbeln

         FROM ekes

         WHERE ebeln = p_ebeln

           AND ebtyp = 'LA'."Inbound Delivery

     ENDIF:

  ENDIF.



Initial value check in SE11 table

$
0
0

While designing new table, we often enable the initial value check to set the initial value for the field based on the datatype.

 

test.JPG

 

A field can also be created in the database as NOT NULL if the initial flag is not set in the ABAP Dictionary.

 

To see  the default value of each field check

 

Utilities ->Database object->Display in the maintenance screen of the corresponding table.

 

test.JPG

 

But in select query there are some impact

 

NULL means that physically nothing is stored in the database. If a database field is defined as CHAR with, say, 80 characters, the NULL value will not waste that space.

 

When NULL values are transfered from the database, they are converted to the ABAP initial value. But if existing database tables are extended appending new field(s), those fields get stored as NULL values for the existing database records. A WHERE <field> = SPACE will not retrieve the recors with NULL values for the field.

 

If such a null field is used in WHERE clause, no problem if specifying any values except initial.
If selection of records with initial fields is required  and  you do not know if NULL values exist, select

 

WHERE ( <field> = space or <field> is NULL ).

 

So we have to check this aspect of table while doing programming.

FQEvent 2638 INV: Enrich Invoicing Item for Invoicing List, current functionality

$
0
0

Functionality


Event 2638 is processed when an invoice with SUBINV item type is created. In this event, you have the option to change relevance (TOTALREL field) of SUBINV item.


If SUBINV item value of TOTALREL field is set to true item amount will be included in total amount of invoice and business partner is payment responsible for SUBINV item too. In this case source invoice shouldn’t be posting relevant, it will have informative purpose.


If SUBINV item value of TOTALREL field is set to false item amount will not be included in total amount, business partner isn’t payment responsible, item should not be posting relevant and it will have informative purpose.

 


Notes


The event is called at invoicing of the single invoicing document.

 


Programming Restrictions


To ensure the consistency of the system, note that you must not use the following language elements in events, unless they were explicitly declared to be allowed for the given event:

  • COMMIT WORK
  • ROLLBACK WORK
  • CALL FUNCTION 'DEQUEUE ALL'
  • Deletion of locks that you have not set yourself
  • Implicit database commits triggered by RFC calls or by a WAIT statement

  If you update additional data in an event and use the construction PERFORM commit routine ON COMMIT, note that: 

  • At the end of the commit routine, all internal tables from which data was updated must be initialized again to prevent a duplicate update in the next call.
  • A PERFORM rollback routine ON ROLLBACK must also be called.
    In the rollback routine, initialize the same data that is initialized at the end of the commit routine.

If you want to carry out checks in an event, when you issue messages, note that warning messages cause background processing of the process to terminate. You should therefore avoid issuing warning messages if possible. At the most, issue warning messages if the value of SY-BATCH is initial.

Also avoid messages of type A (termination). In the course of background processing, such messages can be captured and processing can continue. However, at the same time the message triggers an implicit ROLLBACK WORK, which can cause data inconsistencies.

How to Print Barcodes that are not supported by SAP using Smartforms

$
0
0

Introduction:

 

In this document we will work on printing a Data Matrix barcode (DMC) which is a 2D barcode not supported by SAP.

 

A 2D (two-dimensional) barcode is a graphical image that stores information both horizontally -- as one-dimensional bar codes do -- and vertically. As a result of that construction, 2D codes can store up to 7,089 characters and possibly more.

 

Below are some of the types of 2D barcodes

 

Capture.PNG

Requirement:

 

Print Data Matrix barcode (2D barcode) on zebra printers using Smartform.

 

* Similar approach can be followed for printing other 2D barcodes and the generic barcodes with specific height and width.

 

Issue:

 

SAP by default only supports PDF417 as 2D barcode and does not support Data Matrix and other 2D barcodes

 

Solution:

 

Printing other 2D barcodes which are not supported by SAP is possible by following the below steps

 

  • Printer should supports the required barcode:We can check this online based on the printer model and make. Most probably you will find this information on the manufacturer’s website.

    

  • Choose an appropriate device type for the printer:Selection of device type is based on the printer you are using.  IN this example we are using ZEBRA printer so the device type selction will be based on Zebra printer.This topic is dealt in more detail in the other document named ‘Working with Zebra Printers using Smartforms in SAP’ please refer to the same for additional documentation on selecting the device type for Zebra printers.  For Zebra printers we have the following device types LZEB* (* => 2/3/4) series or YZB# (# => 200/300/400) series based on the DPI resolution of the printer.

        For the demonstration as an example we will use LZEB2 device type from here on in this document.

  • Create a system barcode of type UNDEF in SAP:For creating a system barcode go to transaction SE73.

          This will take you to the SAP script Font Maintenance: Initial screen

        Capture.PNG

          Select System barcodes check box and click the change button. This will display a list of all the Barcodes on the SAP system.

 

          Click the Create button (Paper icon) at the top of the screen

          Capture.PNG

          The Choose Bar Code Technology select box will now be displayed.

          Capture.PNG

          The barcode we are adding is a new barcode symbology which is not supported by SAP, and the new barcode techcnology allows only specif types

          of barcodes symbologies to be created therefore we are going to use Old technology to create our new barcode as an undefined symbology.

 

          So Click on Old.

 

          The Create/Change System Bar Code settings screen will be displayed. For barcode type enter ‘UNDEF’ ( barcode not defined) as the data matrix

          barcode type is not defined in SAP. Also specify the height and width of the barcode.

 

          Capture.PNG

          Then save the changes by clicking on the Ok button. Now the system barcode ZDMC is created.

 

  • Create a printer barcode for the newly created system barcode with appropriate print control:

    

       For creating a system barcode go to transaction SE73. This will take you to the SAP script Font Maintenance: Initial screen

       Capture.PNG

          Select printer barcodes check box and click the change button. This will display a list of device Types available in SAP system.

    

       Capture.PNG

          In this case I am using device type LZEB2 so I will create a printer barcode for this device type. It is advisable to copy this device type to a new

             device type and then make changes to the new Z device type and use it for printing but for demonstration I am using the same device type.

 

             Double click on the device type to list the barcodes supported by this device type.

              Capture.PNG

               Notice the Prefix and Suffix value ranges used for the barcodes. Here in this case the highest number used for prefix is SBP20 and is different

               for each barcode however the suffix is same for all the barcodes. These prefix and suffix are the print controls of the barcodes supported by

               the printer.

 

               Now select the create button on the top of the screen to add a new printer barcode. This will take you to the barcode selection screen.

               Capture.PNG

               Select the system barcode you created earlier and enter the other values as shown in the screenshot above. For prefix we are entering SBP21

               because all the numbers from 1 -20 (SBP01 to SBP20) are already used so we are using the next available number SBP21 and the suffix number

               stays the same. We can use any number from 21-99 for prefix.

 

               Now the barcode is created for the device type (see screen shot  below)

               Capture.PNG

               But the print control SBP21 is empty. For the barcode to work properly we have to add commands in the print control in ZPL-II language

               (printer language).

 

               Please find the online document named 'ZPL2 command book' . The site link for the same is

               http://www.zebra.com/id/zebra/na/en/documentlibrary/manuals/en/zpl_ii_programming2.File.tmp/45541L-002_RA.pdf

 

               It is adviced to have the document before we proceed further. This command book has all the commands for printing different types of

               barcodes on a printer ( only if the printer supports it )using the ZPL2 command Lanugage.

 

               Here we are adding the Data matrix barcode, and the printer command format for printing the data matrix is: ^BXo,h,s,c,r,f,g

 

               Command Parameters:

               O – Orientation

               H – Height

               S – Quality level

               C – Columns to encode

               R – Rows to encode

               F – Format ID

               G – Escape sequence control character

 

               Refer to the attached command book for accepted and default values for the above parameters and how to use the command.

 

           Below is an example of the post script language commands used for printing a DMC barcode on the printer.

           Capture.PNG

            The printer command mainly needs to have 3 types of information

  1.      Command to indicate the type of barcode to be printed ( Marked by ^BX in the command above)
  2.        Command to indicator the start of data ( Marked by ^FD)
  3.        Command to indicator the end of data (Marked by ^FS)

 

           When working with Smartforms the prefix print control in the printer barcodes screen should have both the commands for the type of barcode

               and the command for the start of datawhereas the suffix will only have the command to mark the end of data.

 

           Capture.PNG

          Taking the above points into consideration we will have ^BXN,2,200,20,20,6,~,1^FDcommand in prefix and ^FS in suffix.  As the suffix is

             used to mark the end of data it is same for all the barcodes and hence maintained as default.

 

             Meanings of the command Parameters for prefix ^BXN,2,200,20,20,6,~,1^FD are:

              ^BX        The Data Matrix command

              N            The orientation is normal

              2              Dimensional height in dots of the individual symbol elements

              200         Quality ECC level (ECC 200)

              20           Columns to encode

              20           Rows to encode

              6              Data to be used (6 means full 256 ISO 8-bit data is used)

              ~             Escape sequence for control characters

              1              Square aspect ratio, if you required rectangle this will be 2

              ^FD        This is to mark the start of the field data to be encoded in the barcode

 

            Add the following command in the print control prefix:  ^BXN,2,200,20,20,6,~,1^FD

 

            Go to SE73 -> Select printer barcodes -> Change ->Select device type (in this case LZEB2) -> double click to display the list of barcodes supported

            by the device type.

          Capture.PNG

              Select the new print control SBP21 (barcode prefix) and click on Maintain Print control button. Following popup will be displayed.

          Capture.PNG

              Enter the command in the control characters sequence field and make sure the Hexadecimal switch is turned OFF. Then press enter.

              The print control is saved.

 

               The barcode suffix SBS00, which is default for all the barcodes holds the end of data command (see below)

           Capture.PNG

               The configuration of the printer barcode is complete. Now we can use this barcode to print the Data Matrix barcode (2D barcode) from SAP.

 

               Note:

               There can be various combinations to the prefix command. If the barcode is not printed then you have to try changing the values for the height,

               rows and columns variables in the command. The prefix combination that worked for me is: ^BXN,3,200,,,6,~,1^FD

 

               Capture.PNG

  • Use the barcode in the Smartform using a style:

    

       Please refer to online documentation for adding a barcode to a style in Smartform.

 

       After you have added the barcodes to one of the character formats of the style which is being used in the Smartform, we just have to use the

         newly created barcode type to display the 2D content as Data Matrix Barcode.

 

       See below screenshot for an example.

       Capture.PNG

       As the example depicts, use a separate text node for the 2D barcode , keep all the 2D content in a variable or write it all down in the text node.

         Select the whole text and select the character format for the DMC barcode.

        

          At this point if you try to print the barcode it is expected to see the barcode on the printout, but you might not see the barcode printed on the

         printer, the reason as i understood is that based on the ZPL2 command the data should be marked with the start of data command and End of data

         command along with the type of barcode we are trying to print. so the commands should be inserted before and after the text node that holds

          the 2D data content. This will give the printer a command saying that the data between this is to be printed as the barcode symbology specified in

          the command, in our case Data Matrix.

 

          Note : Preview will not show the barcode because literally this barcode is not in SAP system and will only be printed on the printer. So anything

          concerning the barcode has to be tested on the actual printer not the preview because both the preview and the actual print will be a lot

          different.

 

  • Create a command node before and after the text node that holds the 2D barcode content:

 

       See below screen shots for an example on how to create a command node.

   Capture.PNG

        Then enter the prefix print control we created in the printer control input field (see below).

    Capture.PNG

       Create one more command node under the 2d content text node and enter the enter the suffix print control in the printer control input

         field (see below)

    Capture.PNG

        Now test the print on the Zebra printer, the barcode should be printed on the zebra printer as shown in the screen shot below. Now take the

        printout and scan the barcode with any of the android apps or any barcode reader that support DMC barcode. Please note that the printout taken

        on your local printer from a scanned document wont be readable, so it is advised to test the barcode scanning from the actual printout or from the

        Scanned document on your computer.

       Capture.PNG

        After scanning, the barcode should display all the 2D content .

 

 

Alignment issues with the 2D barcode:

          After the barcode is printed you might notice alignment issues on the label. To solve the alignment issues the following approach can be used.

 

          Go to Smartstyle you have used in the Smartform, select the respective paragraph format node you have assigned for the barcode. Here try

          changing the alignment and spacing values (see screen shot below) and try giving it a few trials. You will be able to align barcodes after a few

          combinations.

 

          Capture.PNG

 

               Note:

               Please make sure you have enough space for the barcode when designing the layout. I mean if you are planning to have a barcode of size

               1 CM * 1 CM then make use you have a separate window on the layout with space more than the barcode size.

 

 

                                                 ----------------  THE END  -----------------

Please note that the document is based on my personal experience and the online documentation i came across. So if there is any scope of improvements in this document you are most welcome.

 

 

         

 

    

To add validation for vendor accounts in MIRO t-code

$
0
0

MIRO T-code:

It is used for entering vendor invoice details received into SAP for incoming Invoice in SAP. All invoice details such as basic data, payment details, tax details etc. can be entered using this t-code. Once the user has input the details of the invoice at the basic data, he will go to the payment tab; there is a small icon to choose the bank account for the vendor.

Because of overlook of this icon (if there are multiple bank accounts or not), user may end up with failed wires (wrong currency paid to the bank account) and this may result in bad consequences as vendor received lesser $ for the exchange rate different.

Requirement:

To display a warning/information message if the vendor has more than one bank account, so that the user can select the correct bank account from payment tab.

Solution:

Once a user enters a Date, PO number and hits ENETER

The system will check in background whether the relevant vendor has more than one bank account or not from Table LFBK

If that vendor has more than one BANK account in table LFBK, a warning popup will be displayed.

For this the BADI ‘MRM_HEADER_CHECK’ was implemented.

MRM_HEADER_CHECK:

Along with the checks in the standard system when entering invoices in the Logistics Invoice Verification, you can use the BADI MRM_HEADER_CHECK to execute customer-specific checks for header and item data of an invoice document. Depending on the checks, the system may, for example, issue an error message or call other transactions.

Step 1:

Go to T-code se-18 and give the BADI name to be implemented.

 

Step 2:

Implement the BADI using Implementation option as below –

Capture1.JPG

Capture2.JPG

Step 3:

Implement the logic in your z implementation of BADI in following way –

 

Capture3.JPG

The class has following parameters:

 

Capture4.JPG

You can implement the logic in based on the vendor number (LIFNR) passed in I_RBKPV parameter.

·         Select the bank details from LFBK table based on LIFNR in an internal table.

·         Describe the internal table, if there are more than one no of lines, issue the relevant message.

 

Following is code implemented -

 

Capture5.JPG

 

Result-

An information message is displayed if the vendor has more than one bank account as below:

Capture6.JPG

Due to the warning message the user will be warned of existing accounts of vendor so that he can check if the correct currency paid to the bank account before final posting.

Jaro–Winkler Distance Algorithm

$
0
0

To tackle a real world problem of the hiring department performing a new hire instead of a rehire for seasonal contractors, I decided to implement the Jaro-Winkler algorithm in SAP.   Since there is a policy to not store key information on contractors (such as SSN), there is only the ability to match on a person’s name.  Unfortunately, the name is not always typed correctly which leads to the inability to find a previous hire and this leads to hiring a new contractor instead of rehiring a contractor.  Using the Jaro-Winkler algorithm, we are now able to suggest possible similar contractors based on the string comparison of first and last name.  Jaro-Winkler calculates the distance (a measure of similarity) between strings.  The measurement scale is 0.0 to 1.0, where 0.0 is the least likely and 1.0 is a positive match.  For our purposes, anything below a 0.8 is not considered useful.

 

“Jaro–Winkler distance (Winkler, 1990) is a measure of similarity between two strings”.

See Wiki link:  http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance  for more in depth information.

p.jpg

 

The Class:  ZCL_JARO_WINKLER

 

Method: STRINGDISTANCE

 

method stringdistance.

 
data: firstlen type i, secondlen type i, halflen type i, commonmatches type i, common1 type string, common2 type string.

 
data: transpositions type i, i type i, j type i.

 
if ( not ( firstword is initial ) and not ( secondword is initial ) ).

   
if ( firstword eq secondword ).

      stringdistance
= totalmatchscore.

   
else.

      firstlen
= strlen( firstword ).

      secondlen
= strlen( secondword ).

      halflen
= zcl_jaro_winkler=>math_min( num1 = firstlen num2 = secondlen ) / 2 + 1.

      common1
= zcl_jaro_winkler=>getcommoncharacters( firstword = firstword secondword = secondword distance = halflen ).

      commonmatches
= strlen( common1 ).

     
if ( commonmatches eq 0 ).

        stringdistance
= totalmismatchscore.

     
else.

        common2
= zcl_jaro_winkler=>getcommoncharacters( firstword = secondword secondword = firstword distance = halflen ).

       
if ( commonmatches ne strlen( common2 ) ).

          stringdistance
= totalmismatchscore.

       
else.

          transpositions
= 0.

         
i = 0.

         
while ( i lt commonmatches ).

           
if ( common1+i(1) ne common2+i(1) ).

              transpositions
= transpositions + 1.

           
endif.

           
i = i + 1.

         
endwhile.

          transpositions
= transpositions / 2.

          stringdistance

               = commonmatches / ( 3 * firstlen ) + commonmatches / ( 3 * secondlen ) + ( commonmatches -transpositions ) / ( 3 * commonmatches ).

       
endif.

     
endif.

   
endif.

 
else.

    stringdistance
= totalmismatchscore.

 
endif.

endmethod.

 

 

Method: GETCOMMONCHARACTERS

 

method getcommoncharacters.

 
data: firstlen type i, secondlen type i, i type i, j type i, ch type c, foundit type c, secondword_copy type string.

 
data: first_half type string, second_half type string, next_start_point type i, remaining_length type i.

 
if ( not ( firstword is initial ) and not ( secondword is initial ) ).

    secondword_copy
= secondword.

    firstlen
= strlen( firstword ).

    secondlen
= strlen( secondword ).

   
i = 0.

   
while i lt firstlen.

      ch
= firstword+i(1).

      foundit
= bool_false.

      j
= zcl_jaro_winkler=>math_max( num1 = 0 num2 = ( i - distance ) ).

     
while ( ( foundit = bool_false ) and ( j lt zcl_jaro_winkler=>math_min( num1 = ( i + distance ) num2 = secondlen ) ) ).

       
if ( secondword_copy+j(1) eq ch ).

          foundit
= bool_true.

         
concatenate commons ch into commons.

         
move secondword_copy+0(j) to first_half.

          remaining_length
= ( secondlen - j ) - 1.

          next_start_point
= j + 1.

         
move secondword_copy+next_start_point(remaining_length) to second_half.

         
concatenate first_half '#' second_half into secondword_copy.

       
endif.

        j
= j + 1.

     
endwhile.

     
i = i + 1.

   
endwhile.

 
else.

   
clear commons.

 
endif.

endmethod.

 

 

Creating a test program:

 

This test program requires that a first name and last name be input by the user and then these names are compared against every employee for possible matches.

 

    loop at t_pa0002 assigning <fs>.

     
translate <fs>-nachn to upper case.

     
translate <fs>-vorna to upper case.

     
move <fs>-nachn to l_compare.

     
call method zcl_jaro_winkler=>stringdistance

       
exporting

          firstword     
= s_nachn

          secondword    
= l_compare

        receiving

          stringdistance
= <fs>-nachn_score.

     
move <fs>-vorna to l_compare.

     
call method zcl_jaro_winkler=>stringdistance

       
exporting

          firstword     
= s_vorna

          secondword    
= l_compare

        receiving

          stringdistance
= <fs>-vorna_score.

      <fs>
-total_score = <fs>-nachn_score + <fs>-vorna_score.

   
endloop.

   
sort t_pa0002 by total_score descending.

   
format color col_normal.

   
write: 80 'Total Score      ' color col_total.

   
uline.

   
loop at t_pa0002 assigning <fs>.

     
write: / <fs>-nachn(20), <fs>-nachn_score, <fs>-vorna(20), <fs>-vorna_score.

     
write 80 <fs>-total_score color col_total.

   
endloop.

 

Deliberately misspelling my last name and shortening my first name:

p.jpg

Results:

p.jpg

 

I only show the top three results.  In fact, since I’m creating a combined score of two different measurements, I would likely consider anything below a 1.60 as not useful in real world.  So now we have a safeguard to alleviate hiring when we should be re-hiring.  Of course, there are many uses for this algorith, such as zip code verification for zip+4.  Also, another use is using as a dictionary check for valid words.

Adding Validation to F-43

$
0
0

Following t-codes are available to use validation or substitution functions:

·         GGB0     Validation Maintenance

·         GGB1     Substitution Maintenance

·         GCVZ     Rule Maintenance

·         GGB4     Select action for validation/substitution, for example, activation of application areas, message usage or substituted fields

·         GCX2     Definition of Includes for User Exits

·         OB28     Activation of FI validations

·         OBBH     Activation of FI substitutions

·         OBBZ     Activation of cost of sales accounting substitution (in the FI area)

·         OKC7     Activation of CO validations

·         OKC9     Activation of CO substitutions

·         GCT9     Transport: Validations

·         GCT0     Transport: Substitutions

To add validation, we take GGB0 in account.

Scenario:

To display a warning/information message in f-43, if the vendor has more than one bank account, so that the user can select the correct bank account of vendor.

Step 1-

Go to GGB0 and create your validation. Here you have 3 things –

·         Prerequisite

·         Check

·         Message

You can relevant prerequisite for your validation, a check and the message you want to display on the check.

Following is the validation step for the taken scenario –

In financial accounting,

Select line item level and create validation

Capture1.JPG

Capture2.JPG

Step 2:

You can now implement your validation/exit through the program RGGBR000. For this, you should copy it into the customer namespace, for example ZGGBR000.

The length of the name you choose should not exceed 8 characters.

Step 3:

To define your new user exit, you have to enter your user exit in the form routine GET_EXIT_TITLES.

Capture3.JPG

Step 4:

Implement your logic in your exit routine as below –

Capture4.JPG

Step 5:

Once you have implemented your logic, you need to activate your exit and define a call up point (header or line item). This is done using t-code OB28 as shown below –

Capture5.JPG

Once you validation has entry here, it will be triggered. In taken scenario, while posting in F-43,

If vendor has more than one bank account, a warning message should be displayed. For the applied logic, please see the result below.

Capture6.JPG

BILL OF MATERIAL (BOM IN SAP) - CS01

$
0
0
This Documents Defines what is BOM and Creation of BOM in ECC (CS01) with sample Test Case.

 

Definition of BOM:

 

For manufacturing a product or assembling, list of several components (part of product) are needed.


A well-structured list of Items or Components is known as BOM - Bill of Material.


The list will contain object number of each components and its unit of measure with quantity.


A finished product is a combination of several different component parts or Materials.

Types of BOM available in SAP

 

You can create the following BOMs in the SAP system:


  • Material BOMs
  • Equipment BOMs
  • Functional location BOMs
  • Document structures
  • Order BOM
  • Work breakdown structure (WBS) BOM


BOM can be act as basic for several activities in Production department , some of the examples are :


1.MRP Department:


BOM data can be used to calculate cost-effective order quantities for materials.

 

2.Work scheduling department:

BOM data can be used for operation planning and control.

 

3.Production order management department:

          BOM data can be used to plan the provision of materials.

3. Sales Order


4. Reservation


5. Product Costing

 

BOM Usage :


It is a Key which defines different areas of a Company where the BOM can be used.


BOM Item Category :

 

Categorization of the items in a BOM according to set criteria, such as whether they refer to an object or whether they are kept in stock.

 

  • This categorization allows you to process data that is relevant to the individual items in a BOM. The item category is used to control field selection, default values for BOM maintenance, triggering of specific system activities, and so on.

 

  • For Example Documentation Item, Stock Item, Packing Item.


  • SAP R/3 system allows you to create individual BOM depending upon the area in your company.

 

Define BOM Usages:

 

  1. In Customizing for Production, define individual BOM usages for the different areas within your company by choosing Basic data -->Bill of Material --> General data -->BOM usage -->Define BOM usages.

 

You can define BOM usages for the following scenarios:


  • You maintain separate BOMs for different areas within your company, such as design or production.
  • You create just one BOM for all areas within your company.


Alternative BOM:


  • Alt BOM is used to define BOM in a BOM group.


  • By default system will consider next ALT. BOM Number if user won’t enter any Alt BOM Number.


  • If user enter any Alt. BOM , then system will validate Alt BOM.

 

Structure of a BOM:

 

BOM data is structured as below,

 

BOM Header:

 

  •      BOM Header consists of DATA Related to BOM, which consists of Plant, Material,Technical Type, Revision Label, etc…

 

  •      BOM Header maintains data refer to entire object .

 

  •      Refer to single Header Multiple BOM’s would be created which will be maintained by ALT BOM.

 

BOM Item :

 

Each part of a final Product is called BOM Item , A product is a collections BOM Items .It consists of Item Number, component Quantity , Item Category, Unit of Measure, Item id .

 

Sub Items:


Partial quantities of a BOM item may be installed at different points. Sub-items are used to describe the different installation points of these partial quantities. Sub-items have no operational function in the BOM.              

 


BOM Creation in SAP ECC


Transaction for BOM creation  is CS01 .


1.Initial Screen for BOM creation :

 

1.png

 

Mandatory Fields for entering into next screen are Material, Plant and BOM Usage as per Requirement and by default Alt will pick up as next value to available Alt BOM.


3.png


Click on Header Icon for header details :


4.png


As shown below by default system with Pick 1 as base Qty and Base UOM will be picked from Material Base UOM.


5.png

 

Create BOM Items :


Enter Item Components along with component Qty,UOM,Item Category as shown below.

 

 

BOM Creation Sample Code in ECC :

Scenario :


Create material  BOM along with items and define Procustion Version .


Define ztables and structure as per the requirement .


Create a class and method for BOM creation with Importing Parameters and exporting parameters as :


I_BOM HEADER

I_BOM_ITEMS

E_RETURN

 

 

 

*Data Declarations

 

  DATA : lit_bom_header     TYPE TABLE OF zsbom_header,

         wa_bom_header        TYPE zsbom_header,

         wa_bom_head           TYPE zsbom_header,

         lit_bom_head            TYPE TABLE OF zsbom_header,

         wa_bom_h                TYPE zsbom_header,

         lit_bom_items           TYPE TABLE OF ztbom_items,

         wa_bom_items         TYPE ztbom_items,

         wa_bom_i                 TYPE zsbom_items,

         lit_bom_items_table   TYPE TABLE OF zsbom_items,

         lit_bom_item_table     TYPE TABLE OF zsbom_items,

         wa_bom_item_table   LIKE LINE OF lit_bom_item_table,

         lit_cost_bom_items   TYPE TABLE OF ztt_bom_item,

         lit_bom_item             TYPE ztbom_items,

         i_mast              TYPE  TABLE OF mast,

         lv_role             TYPE zrole,

         lv_verid            TYPE mkal-verid,

         lv_verid1           TYPE mkal-verid,

         lv_bstma            TYPE char13,

         lv_bstmi            TYPE char13,

         lv_stlal            TYPE stlal,

         lv_idnrk            TYPE idnrk,

         lv_flag             TYPE char1,

         lv_phassign(4)      TYPE c,

         lv_ph_desc          TYPE string,

         wa_error            TYPE bapiret2,

         lit_error           TYPE TABLE OF bapiret2,

         persistent_ref      TYPE REF TO zcl_d_persist_bom,

         obj_ref             TYPE REF TO zcl_d_bom,

         l_msg               TYPE bapiret2-message,

         l_warnings          TYPE capiflag-flwarning,

         l_stpo              TYPE TABLE OF stpo_api02,

         wa_stpo             LIKE LINE OF l_stpo,

         l_stko              TYPE TABLE OF stko_api02,

         lv_matnr            TYPE csap_mbom-matnr,

         timestamp           TYPE tzonref-tstamps,

         obj_bom             TYPE REF TO zcl_d_bom.

 

  TYPES : BEGIN OF ty_mast,

              matnr TYPE mast-matnr,

              werks TYPE mast-werks,

              stlan TYPE mast-stlan,

              stlal TYPE mast-stlal,

            END OF ty_mast.

 

  DATA : lit_mast  TYPE STANDARD TABLE OF ty_mast,

         wa_mast   TYPE ty_mast,

         lit_mast1 TYPE TABLE OF mast,

         lv_index  TYPE sy-tabix,

         lv_itmid  TYPE bapi1080_itm_c-item_id.

 

  DATA : bom_items         TYPE STANDARD TABLE OF zsbom_items,

         lit_bom_item_temp TYPE  STANDARD TABLE OF zsbom_items.

 

 

  DATA : lit_stas  TYPE TABLE OF stas,

         wa_stas   TYPE stas,

 

         lit_ausp  TYPE TABLE OF ausp,

         wa_ausp   TYPE ausp,

 

         wa_mast1  TYPE mast,

 

         lit_stpo1 TYPE TABLE OF stpo,

         wa_stpo1  TYPE stpo,

 

         lit_inob  TYPE TABLE OF inob,

         wa_inob   TYPE inob.

 

  DATA : lv_objek   TYPE inob-objek,

         lv_date    TYPE rn1datum-datex,

         lv_stlnr   TYPE mast-stlnr,

         lv_counter TYPE i.

 

  DATA : lit_bom_hrep      TYPE TABLE OF ztbom_head_rep,    "Historical Report declarations

         wa_bom_hrep        TYPE ztbom_head_rep,

         wa_bom_hrep1       TYPE ztbom_head_rep,

         lit_bom_hist_temp  TYPE TABLE OF ztbom_head_rep,

         wa_bom_hist_temp  TYPE ztbom_head_rep,

         wa_bom_hist_temp1 TYPE ztbom_head_rep,

         lit_ampl          TYPE TABLE OF ampl,

         wa_ampl           TYPE ampl,

         lit_bom_irep      TYPE TABLE OF zsbom_i_report,

         wa_bom_irep       TYPE zsbom_i_report,

         wa_bom_itemrep    TYPE ztbom_item_rep,

         lit_hist_msg      type ztd_hist_msgs,

         wa_hist_msg       type ztd_hist_msgs.

 

* internal table that have to be passed to the bapi

          DATA :  lit_bomgroup TYPE STANDARD TABLE OF bapi1080_bgr_c,

                  wa_bomgroup   TYPE bapi1080_bgr_c,

                  lv_bom_text   TYPE string,

                  lv_plant      TYPE ztbom_header-werks,

 

                   lit_variants TYPE STANDARD TABLE OF bapi1080_bom_c,

                   wa_variants  TYPE bapi1080_bom_c,

 

                   lit_items    TYPE STANDARD TABLE OF bapi1080_itm_c,

                   wa_items     TYPE bapi1080_itm_c,

 

                   lit_matrel   TYPE STANDARD TABLE OF bapi1080_mbm_c,

                   wa_matrel    TYPE bapi1080_mbm_c,

 

                   lit_itemas   TYPE STANDARD TABLE OF bapi1080_rel_itm_bom_c,

                   wa_itemas    TYPE bapi1080_rel_itm_bom_c.

 

 

*-->Check BOM Existency

 

          CALL FUNCTION 'CONVERSION_EXIT_MATN1_INPUT'

            EXPORTING

              input  = i_bom_header-matnr

            IMPORTING

              output = lv_matnr.

 

 

          SELECT SINGLE stlnr FROM mast INTO lv_stlnr WHERE matnr = lv_matnr

AND werks = i_bom_header-werks

AND stlal = i_bom_header-stlal AND stlan = '1'.

          IF lv_stlnr IS  INITIAL.

 

*  assign bom usage to 1.

            IF wa_bom_h-stlan IS INITIAL.

              wa_bom_h-stlan = zif_d_constant=>c_production_bom_usg.

            ENDIF.

 

* assign bom text bases on condition

            lv_plant = wa_bom_h-werks.

            IF lv_plant+0(2) = '10'.

              CONCATENATE 'BOM For' wa_bom_h-maktx INTO lv_bom_text SEPARATED BY space.

            ELSE.

              lv_bom_text = ' ' .

            ENDIF.

 

wa_bomgroup-bom_group_identification = 'BAPI_SMP_COL1'.

            wa_bomgroup-object_type = 'BGR'.

            wa_bomgroup-object_id = 'SIMPLE1'.

            wa_bomgroup-bom_usage = wa_bom_h-stlan.

            wa_bomgroup-created_in_plant = wa_bom_h-werks.

            wa_bomgroup-ltxt_lang = sy-langu.

            wa_bomgroup-technical_type = ' '.

            wa_bomgroup-bom_text = lv_bom_text.

            APPEND wa_bomgroup TO lit_bomgroup.

 

            IF wa_bom_h-datuv IS INITIAL.

              wa_bom_h-datuv = sy-datum.

            ENDIF.

 

*UOM Conversion :

 

            CALL FUNCTION 'CONVERSION_EXIT_CUNIT_INPUT'

              EXPORTING

                input          = wa_bom_h-bmein

              IMPORTING

                output         = wa_bom_h-bmein

              EXCEPTIONS

                unit_not_found = 1

                OTHERS         = 2.

 

*Define Varaints

 

wa_variants-bom_group_identification = 'BAPI_SMP_COL1'.

            wa_variants-object_type              = 'BOM'.

            wa_variants-object_id                = 'SIMPLE1'.

            wa_variants-alternative_bom          = wa_bom_h-stlal.

            wa_variants-bom_status               = wa_bom_h-stlst.

            wa_variants-base_qty                 = wa_bom_h-bmeng.

            wa_variants-base_unit                = wa_bom_h-bmein. " base unit

            wa_variants-alt_text                 = wa_bom_h-alternate_text.   " alternative text

            wa_variants-valid_from_date          = wa_bom_h-datuv.

 

            wa_variants-function = 'NEW'.

            APPEND wa_variants TO lit_variants.

 

            CLEAR lv_itmid.

            LOOP AT bom_items INTO wa_bom_i.

              CLEAR wa_items.

 

              MOVE-CORRESPONDING wa_bom_i TO wa_bom_items.

 

              IF wa_bom_items-posnr IS INITIAL.

                wa_bom_items-posnr = '0010'.

              ENDIF.

 

              IF wa_bom_items-postp IS INITIAL.

                wa_bom_items-postp = 'L'.

              ENDIF.

 

              IF wa_bom_items-datuv IS INITIAL.

                wa_bom_items-datuv = sy-datum.

              ENDIF.

 

              CALL FUNCTION 'CONVERSION_EXIT_MATN1_INPUT'

                EXPORTING

                  input        = wa_bom_items-idnrk

                IMPORTING

                  output       = wa_bom_items-idnrk

                EXCEPTIONS

                  length_error = 1

                  OTHERS       = 2.

 

 

* Details of the items of the variants

 

*to convert the uom for bom item

 

              CALL FUNCTION 'CONVERSION_EXIT_CUNIT_INPUT'

                EXPORTING

                  input          = wa_bom_items-meins

                  language       = sy-langu

                IMPORTING

                  output         = wa_bom_items-meins

                EXCEPTIONS

                  unit_not_found = 1

                  OTHERS         = 2.

 

              CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'

                EXPORTING

                  input  = wa_bom_items-vendor_no

                IMPORTING

                  output = wa_bom_items-vendor_no.

 

              wa_items-bom_group_identification = 'BAPI_SMP_COL1'.

              wa_items-object_type              = 'ITM'.

              wa_items-object_id                = 'SIMPLE1'.

              wa_items-item_no                  = wa_bom_items-posnr.

              wa_items-item_cat                 = wa_bom_items-postp ."Item Category

              wa_items-comp_unit                = wa_bom_items-meins. " bom uom added

              wa_items-alt_item_prio            = wa_bom_items-alprf. " priority added

              wa_items-usage_prob               = wa_bom_items-ewahr. " usage probability added

 

*-->Sort String

              IF wa_bom_items-sortf IS NOT INITIAL.

                wa_items-sort_string              = wa_bom_items-sortf." sort string added

              ELSE.

                SPLIT wa_bom_items-zph_assign AT '-' INTO lv_phassign lv_ph_desc.

                CONDENSE lv_ph_desc.

                wa_items-sort_string              = lv_ph_desc .

 

              ENDIF.

*-->End of Sort String

 

              wa_items-component                = wa_bom_items-idnrk.

              wa_items-comp_qty                 = wa_bom_items-menge.

              wa_items-item_text1               = wa_bom_items-ktext. "Bom component description added

              wa_items-alt_item_group           = wa_bom_items-alpgr.  " Bom Alt Item Group

              wa_items-valid_from_date          = wa_bom_items-datuv.

              wa_items-iss_st_loc               = wa_bom_items-lgort."storage plant

 

 

*-->Alt Item Strategy

              IF wa_items-alt_item_group IS NOT INITIAL.

                wa_items-alt_item_strategy = '2'. "Alt Item Strategy

              ELSE.

                wa_items-alt_item_strategy = ' '.

              ENDIF.

 

              IF wa_bom_items-idnrk CP '35*'.

                wa_items-class_type        = '023'.

                wa_items-vendor_no         = wa_bom_items-vendor_no.

              ENDIF.

 

              APPEND wa_items TO lit_items.

              CLEAR  wa_items.

            ENDLOOP.

 

            CLEAR lv_itmid.

 

            CALL FUNCTION 'CONVERSION_EXIT_MATN1_INPUT'

              EXPORTING

                input        = wa_bom_h-matnr

              IMPORTING

                output       = wa_bom_h-matnr

              EXCEPTIONS

                length_error = 1

                OTHERS       = 2.

 

*creation of production BOM

 

            IF wa_bom_h-stlan IS INITIAL.

              wa_bom_h-stlan = 1.

            ENDIF.

 

*--From Lot size and to size------------*

 

            IF i_bom_header-werks CP '10*'.

 

              lv_bstmi = zif_d_constant=>c_bstmi.  "BASE QUANTITY

              lv_bstma = zif_d_constant=>c_bstma.

              CONDENSE lv_bstma.

              CONDENSE lv_bstmi.

            ELSE.

 

              lv_bstmi = zif_d_constant=>c_bstmi.

              lv_bstma = zif_d_constant=>c_bstma.

              CONDENSE lv_bstma.

              CONDENSE lv_bstmi.

            ENDIF.

 

* Details of the materials of the different variants

            wa_matrel-bom_group_identification = 'BAPI_SMP_COL1'.

            wa_matrel-material                 = wa_bom_h-matnr.

            wa_matrel-plant                    = wa_bom_h-werks.

            wa_matrel-bom_usage                = wa_bom_h-stlan.

            wa_matrel-alternative_bom          = wa_bom_h-stlal.

            wa_matrel-lot_size_from            = lv_bstmi.

            wa_matrel-lot_size_to              = lv_bstma.

            APPEND wa_matrel TO lit_matrel.

 

* Linking items to the corresponding variants

            wa_itemas-bom_group_identification = 'BAPI_SMP_COL1'.

            wa_itemas-sub_object_type          = 'ITM'.

            wa_itemas-sub_object_id            = 'SIMPLE1'.

            wa_itemas-super_object_type        = 'BOM'.

            wa_itemas-super_object_id          = 'SIMPLE1'.

            wa_itemas-valid_from_date          = wa_bom_items-datuv.

            wa_itemas-function                 = 'NEW'.

            APPEND wa_itemas TO lit_itemas.

 

* call function to create bill fo materail by using

* the previously declared local internal tables

 

            SORT lit_items BY object_id valid_from_date.

            CALL FUNCTION 'BAPI_MATERIAL_BOM_GROUP_CREATE'

              EXPORTING

                all_error         = 'X'

              TABLES

                bomgroup          = lit_bomgroup

                variants          = lit_variants

                items             = lit_items

                materialrelations = lit_matrel

                itemassignments   = lit_itemas

                return            = e_return.

 

            CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'.

 

*----END OF Production BOM CREATION-----------------------*

 

References:

 

http://braincybersolutions.com/sap-tutorials/pp/bom-in-sap-bill-of-material/

http://help.sap.com/saphelp_46c/helpdata/en/ea/e9af734c7211d189520000e829fbbd/frameset.htm


VERSION MANAGEMENT IN SMARTFORMS

$
0
0

The purpose of this document is to compare the versions of smart forms in different servers. This document is highly beneficial for Developers in ABAP which explains a step by step procedure to compare the versions of the forms.

 

INTRODUCTION:

 

Smartform has only one active version, in the form of function module which is regenerated once you change and activate it. Since smartform is client Independent, it can be easily transported to other systems. There may be cases where we would require to compare the versions of the forms across different systems. Though it is not possible to compare the forms directly, it can be achieved to some extent by comparing the generated Function modules line by line, thereby capturing the changes. This can be done via the Transaction SE39-Split Screen editor.

Note that the generated Function Module names will not be same across all systems.

 

PROCEDURE:

Once the smartform is created and activated, a Function Module gets generated.

P1.png

 

To open the Function Module in display mode, either execute the Smartform or go via Transaction SE37 by fetching the FM name from Environment menu.FM will be opened in display mode as follows.

P2.png

Select the Attributes tab and double click on the program name.

P3.png

The following screen appears with the list of file names. Select the required Include name under User defined Files.

p4.png

 

Similarly, the include name is fetched from the other server that needs to be compared.

Now, go to transaction code SE39.The following screen appears.

p6.png

Click on the option ‘Compare different Systems’.

Enter appropriate include names and details of the systems that needs to be compared.

p7.png

Enter the logon details of the system to be compared.

Comparison screen appears. Click on the ‘Comparison On’ button to initiate the process.

p10.png

Select ‘Next Difference from cursor ‘, Next Identical section from cursor’ options to analyze the variations and the same procedure is carried out till the end.           

There is no option to compare the forms directly. But, the entire list of requests available for a smartform can be obtained from which the number of changes done can be captured.

Go to transaction SE03. Select the option ‘Objects in Requests’.  Double click on Search for objects in Requests/Task.

p11.png

 

The screen appears as below. In the Object Selection type, enter the Object type as ‘SSFO’ and give the smartformname and then Execute.

p12.png

List of all the Requests related to that smartform are displayed from which the changes can be traced.

Shared Memory-enabled Classes and Create Data – Area Handle

$
0
0

Summary

Shared Objects are objects in the shared memory. The shared memory is a memory area on an application server, which is accessed by all of this server’s ABAP programs. In this article I am giving a brief idea on Shared Memory-enabled Classes, ‘Create Data – Area Handle’ statement and read/write of shared objects. Sufficient screenshots and sample codes are also provided.

 

Author: Abyson Joseph Chavara         

Company: Applexus Technologies (P) LTD

Created on:  02 April 2012

 

Introduction

Shared Objects are objects in the shared memory. The shared memory is a memory area on an application server, which is accessed by all of this server’s ABAP programs. Before shared objects were implemented, ABAP programs could access this memory area using the EXPORT and IMPORT statements exclusively, but this method was very slow because the "sending" program had to copy variables from its memory to the shared memory, and the "receiving" program had to copy these variables from the shared memory into its own program memory. This generated two copies for basically nothing.  With the implementation of shared objects with Release 6.40, the shared memory was enhanced with the shared objects memory that stores shared objects. Shared objects are stored in what are called shared memory areas. You create and manage areas and their properties using Transaction SHMA.

The benefits of shared objects includes Copy-free: very fast access, version management, preloading, automatic propagation from a database, easy monitoring, etc. In this article I am giving a brief idea on Shared Memory-enabled Classes, ‘Create Data – Area Handle’ statement and read/write of shared objects. Sufficient screenshots and sample codes are also provided.

Shared Memory-enabled Classes

The prerequisite for storing an instance of a class in the shared memory is that the class of the object has to be defined with the SHARED MEMORY ENABLED addition of the CLASS statement, or that the property Shared memory-enabled has to be selected in the Class Builder. Each area is linked with what is called a global area root class, which can contain separate data and references to other instances of shared memory-enabled classes or to anonymous data objects in its own attributes.

Area Classes and Area Handles

When an area is defined in Transaction SHMA, a global and final area class with the same name is generated as a subclass of CL_SHM_AREA. Class CL_SHM_AREA itself is a direct subclass of CL_ABAP_MEMORY_AREA. In an ABAP program, an area is accessed exclusively using the methods of the generated area class. There are static methods for binding an ABAP program (or its internal session) to area instances in the shared memory (attach methods). Binding creates an instance of the area class as an area handle, and creates a lock at the same time. The ABAP program can access the bound area instance version using the area handle and thus access the shared objects that are stored there. The area handle also contains the methods for deleting the connection or the lock (detach methods).

CREATE DATA - AREA HANDLE

This statement creates an anonymous data object as shared object in the area instance version of the shared memory, which is bound to the area handle referenced by handle. For handle, an object reference variable must be specified; whose static type is CL_ABAP_MEMORY_AREA or one of its subclasses (area class). When the statement is executed, handle must point to an area handle and the area handle must be bound to an area instance version with a change lock. To create such a reference, you have the following options:

 

  • Transfer of the return value of the methods ATTACH_FOR_WRITE or ATTACH_FOR_UPDATE of an area class created with SHMA.

 

  • Transfer of the return value of the method GET_HANDLE_BY_OREF of any area class.

 

  • Transfer of the return value of the method GET_IMODE_HANDLE of the predefined class CL_IMODE_AREA.

 

The latter is a reference to an area handle for the current internal mode and the statement CREATE DATA acts like without the addition AREA HANDLE.

 

Example 1

Here is a very simple example showing the steps to create the root class, shared area, and the use of CREATE DATA - AREA HANDLE statement.

 

Step 1: Creating Root class

First of all we have to create a Root class. Go to SE24 and create a new class. Here I have given the name 'ZCL_SHR_AREAHANDLE_ROOT'. Go to the properties tab and check the box Shared Memory -Enabled, as shown in the below image.

01.JPG

 

Step 2: creating attributes

Now go to the attributes tab and create 2 attributes. Here I have named as ‘id_num’, level as instance attribute, visibility as public, associated type as STRING and second one named as ‘dref’, level as instance attribute, visibility as public, associated type as DATA (for Area Handle).  See image below.

02_attribute.JPG

 

Step 3: Assign Interface.

Go to the tab interface and assign the interface “IF_SHM_BUILD_INSTANCE” and activate the class.

03_interface.JPG

Step 4: Creating Area (SHMA)

Now run transaction SHMA and create a area named 'zcl_shr_areahandle_area'. Give 'zcl_shr_areahandle_root' as root class and constructor class. Check the box 'Aut. Area Creation' and 'With Versioning'. Select 'Displacement Not Possible' for 'Displacem. Type' field and 'Autostart for Read Request and Every Invalidation' for 'Area Structure' field. Screen shot shown below.

05_area.JPG

 

 

Step 5: attach_for_write( )

Now go to SE38 and create  a program, for eg. 'ZCL_SHR_AREAHANDLE_SET'. After creating an area handle referenced from 'v_area_handle', an instance of the area root class 'zcl_shr_areahandle_root' of the area is created. In area root class, we have already created a generically typed (using REF TO data) data reference variable named 'dref' as public attribute. With CREATE DATA, you create an anonymous data object in the area instance version, which is fed with a value after it has been assigned to a field symbol.  The sample code is given below.

REPORT  zcl_shr_areahandle_set.

 

DATA: v_area_handle TYPEREFTO zcl_shr_areahandle_area,
v_root        TYPEREFTO zcl_shr_areahandle_root.

FIELD-SYMBOLS <fs_data> TYPEANY.

TRY.
v_area_handle = zcl_shr_areahandle_area=>attach_for_write( ).

CREATE OBJECT v_root AREA HANDLE v_area_handle.

v_area_handle->set_root( v_root ).

*dref is the attribute created in root class.

CREATEDATA v_root->dref AREA HANDLE v_area_handle TYPE string.

ASSIGN v_root->dref->* TO<fs_data>.

<fs_data> = '700'.

v_area_handle->detach_commit( ).


CATCH cx_shm_external_type.

CATCH cx_shm_attach_error.

ENDTRY.

 

Step 6: attach_for_read( )

We can access the shared object, in another program. For that, create another program in SE38 named for eg. 'zcl_shr_areahandle_get'. Sample code given below.

 

REPORT  zcl_shr_areahandle_get.

DATA v_area_get TYPEREFTO zcl_shr_areahandle_area.

FIELD-SYMBOLS <fs_get> TYPEANY.

TRY.
v_area_get = zcl_shr_areahandle_area=>attach_for_read( ).

ASSIGN v_area_get->root->dref->* TO<fs_get>.


WRITE:/  <fs_get>.

v_area_get->detach( ).

CATCH cx_shm_attach_error.

ENDTRY.

You can see the output as displayed below.

07_result.JPG

 

Example 2

In the next example we will add two methods to the root class, for writing and reading values to the shared object.

Step1: Adding methods

Go to the methods tab of the root class. You can see method 'IF_SHM_BUILD_INSTANCE~BUILD' is added automatically. Create two more methods named 'GET_ID_NUM' and ‘SET_ID_NUM’. Set the level and visibility attributes as shown in the image below.

04_methods.JPG

Step 2: Adding parameters to methods

Add a parameter l_msg to the method  'GET_ID_NUM’, type as Returning, as shown below.

06_parameter.JPG

Also add a parameter l_id_num to the method 'SET_ID_NUM', type as Import, and associated type as string.

Step 3:  Area constructor

Double click on the method 'IF_SHM_BUILD_INSTANCE~BUILD’ and add the following code between the 'method IF_SHM_BUILD_INSTANCE~BUILD' and 'endmethod' statements and save.

 

DATA: sh_area TYPEREFTO zcl_shr_areahandle_area,
sh_root TYPEREFTO zcl_shr_areahandle_root.

* Get a pointer to shared area
sh_area = zcl_shr_areahandle_area=>attach_for_write( ).

* Create an instance of the root
CREATE OBJECT sh_root AREA HANDLE sh_area.

* Sets Intial values
sh_root->set_id_num( '999' ).

* set the root back into the area
sh_area->set_root( sh_root ).

* Commit and detach
sh_area->detach_commit( ).

Step 4: Adding code lines in Methods.

Double click on the method 'SET_ID_NUM' and enter the following code between 'method SET_ID_NUM' and 'endmethod' statement and save.

id_num = l_id_num.

Next double click on the 'GET_ID_NUM' method and enter the following code between 'method GET_ID_NUM' and 'endmethod' statement, then save and activate.

 

DATA: lv_id_msg TYPE string.

* Concatenating a title to id_num.
CONCATENATE'Identification Number:' id_num
INTO lv_id_msg.
l_msg = lv_id_msg.

Step 5: 'attach_for_update( )'

Now we are going to set values to the memory by using the method 'attach_for_update'. (Remember we have already initialized the id_num using method 'attach_for_write' in the Area Constructor.) Go to SE38 and create a program named for eg. 'zcl_shr_areahandle_update' and enter the following code and execute.

REPORT zcl_shr_areahandle_update.

DATA: v_area TYPEREFTO zcl_shr_areahandle_area,
v_root TYPEREFTO zcl_shr_areahandle_root.

TRY.
v_area = zcl_shr_areahandle_area=>attach_for_update( ).

CATCH cx_shm_no_active_version.
WAITUPTO1 SECONDS.
v_area = zcl_shr_areahandle_area=>attach_for_update( ).

ENDTRY.

v_root ?= v_area->get_root( ).

IF v_root ISINITIAL.

CREATE OBJECT v_root AREA HANDLE v_area.

ENDIF.

v_root->set_id_num( '800' ).

v_area->set_root( v_root ).

v_area->detach_commit( ).

 

Step 6: ' attach_for_read ( )'

Now we can read the memory from another program. Go to SE38 and create a new program named for eg. 'zcl_shr_areahandle_read' and enter the following code and execute.

 

REPORT  zcl_shr_areahandle_read.

DATA: v_area1 TYPEREFTO zcl_shr_areahandle_area.

TRY.
v_area = zcl_shr_areahandle_area=>attach_for_read( ).
CATCH cx_shm_no_active_version.
WAITUPTO1 SECONDS.
v_area = zcl_shr_areahandle_area=>attach_for_read( ).
ENDTRY.

DATA: v_msg TYPE string,
l_msg TYPE string.
v_msg = v_area->root->get_id_num( ).

WRITE: / v_msg.

v_area->detach( ).

 

You can see that v_msg will print the previously updated value '800' along with the concatenated string 'Identification Number:'

 

Related Content

http://help.sap.com/saphelp_nw70/helpdata/en/c5/85634e53d422409f0975aa9a551297/content.htm

http://help.sap.com/abapdocu_70/en/ABAPCREATE_DATA_AREA_HANDLE.htm

http://help.sap.com/saphelp_nw70/helpdata/en/df/109b8b4b073b4c82da0f2296c3a974/content.htm

ABAPer's Tabloscope-The SAP Table Relationships & Fields Explorer

$
0
0

Please find as attachment, the source codeand find the user manual(with links to download) below.

 

Note:

  1. Check this document regularly for latest version source code as the functionality of this tool being improved further.
  2. Please, rate this document as it will help others to prioritize this among the other available alternative methods to search relationships, on Google search.

________________________________________________________________________________________________________________________________________

 

SAP is like an ocean and often an ABAP consultant looses much of the time in finding relationships among tables and searching for fields, which causeshim/her unnecessary delays. Even SAP quick viewer and other SAP standard search methods doesn't provide him/her with accurate results always and many times they propose very large result set, most of which are irrelevant solutions for the queried scenario. Some problems, an ABAP consultant would usually encounter are:


For example:

 

1. To search for direct relationships between tables 'EBAN' and 'T16FS', the easy method is to go for SAP Quick Viewer (SQVI). But SQVI shows relationships only if the field names, data elements or domains match. So, in this case it shows only one relationship i.e, between FRGGR fields of both the tables but it doesn't show relationship between fields FRGST and FRGSX of tables EBAN and T16FS respectively which can also be related, as both are ' Release strategies'.


 

2.  To search for indirect relationships (link tables) between two tables in the absence of direct relationships.For example, there are no direct relationships between tables 'VBAK' and 'EKKO' and there is no standard method or tool to find indirect relationships i.e., link tables between them than manually checking, which is cumbersome.


 

3. To search for the field with description 'Bill-to party', one usually goes for 'SE80' which is a case-sensitive search. That is, it would show only those fields with the given description in lower case alphabets when the search term is typed as 'bill-to party'. And most of the times a consultant would be aware of the field description but not the cases of alphabets in field description.


 

4. And moreover, with the usual standard methods an ABAPer uses,the result set would be huge with all SAP tables in which the relevant solutions for our scenario  is somewhere in the remote corner. It's like searching for 'Titanic' in Atlantic ocean. It would be more easy to search for 'Titanic' if the Atlantic would be of the size of Lake Superior. I.e., It would make the job of an ABAP consultant more easier if the search  can be carried out separately in each module or application area instead of all SAP.


 

                  With one and a half month effort I developed a tool (overcoming all these limitations and adding some more useful features) which I named as 'ABAPer's Tabloscope' can be a very useful assistant especially for an ABAP consultant.


 

                               USER MANUAL

001.jpg

This is cover page, click on any of the links below to download/view complete user manual:

Tabloscope-User Manual.pptx - Google Drive (PPT)

Tabloscope-User Manual.pdf - Google Drive   (PDF)

 

 

Creation of Custom Kernel BADI and Calling it in a Custom Program

$
0
0

The BADI(Business Add-in's) is an object-oriented enhancement option. The BADI defines an interface that can be implemented by BADI-implementations that are transport objects of their own. The new BADI or Kernel BADI is fully integrated into the Enhancement Framework. Within the Enhancement Framework a BADI is an enhancement option or an anchor point for an object plug-in.

 

Kernel BAdI's Features

  • Are integrated directly in the ABAP Language/Runtime
  • Improved filter support allows non-character filter types and complex filter conditions
  • Enable reusable implementation instances (Stateful BAdI)
  • Control of the lifetime of implementations (BAdI-context)
  • Allow for inheritance of implementations
  • Can be switched by the Switch Framework

 

In this document, I have demonstrated the various steps for creating a Kernel BADI and calling it in our own Custom program.

 

1. First  create a  Enhancement spot from SE18. Kernel Badi's belong to an enhancement spot.

Enhancement spots carry information about the positions at which enhancement options were created. One enhancement spot can manage several enhancement options of a Repository object. Conversely, several enhancement spots can be assigned to one enhancement option.

 

 

Enter the description and if you want you can assign the new enhancement spot to a composite enhancement spot. Composite enhancement spots are used for the semantic grouping of simple enhancement spots. A composite enhancement spot contains either one or more simple enhancement spots and/or one or more composite enhancement spots of the relevant type. You can use composite enhancement spots to combine simple enhancement spots into meaningful units.

 

 

2. On creating the Enhancement spot, you will be directed to Enhancement Spot Editor. Now we need to create a new BADI Definition.

 

 

 

3. Click on the create BADI button.

 

 

4. You will find certain options for the BADI definitions as below.

 

 


Usability - Multiple use - that is, there can be several active implementations

Limited Filter Use – This makes the BADI Filter-dependent - that is, you apply a filter value to each method called (for example, a country). A different (active) implementation is then called for each value. Possible filter values are characterized by the filter type.



Instance Generation Mode - This property controls the instantiation of the object plug-ins during execution of the statement GET BADI.

The first two specifications define context-free BAdIs.

Newly Created Instantiation - New object plug-ins are created at each execution of the statement GET BADI.

Reusing Instantiation - An object plug-in that was used once in the current internal mode is reused, if it is required more than once.

Context-Dependent Instantiation - A context must be specified for GET BADI. This context controls the instantiation. Only one object plug-in is created for each context and implementing class. Each time there is another GET BADI with the same context, it is reused. A context is an instance of a class that implements the tag interface if_badi_context. The specification takes place in the form of a reference to such an instance.



Fallback Class - Fallback class for a BADI is used if there is no active BADI implementation. This means: The GET BADI command returns a handle to an instance of the fallback class and the respective CALL BADI calls the methods of the fallback class instance. As soon as there is an active BADI implementation, the fallback class is not used any longer at runtime.


 

 

5. Now we need to add an interface to the BADI. Expand the Node of BADI definition name and double click on node Interface. You can either add existing interface or will be prompted to create.

 


 

6. On clicking ‘Yes’, you will be navigated to the below screen, where you can add a method to the new interface.


Save, activate and comeback to the BADI definition screen and activate the Enhancement Spot.

 

 

7. Next we need to implement the Enhancement spot and BADI. Right click on the BADI definition and select Create BADI Implementation.

 

 

8. First the system will ask for enhancement implantation name. Please enter a name and description.

 

 

9. Next it will ask for BADI Implementation name and Class name for implementing BADI. Enter the names and click ok.

 

 

10. Next we have to implement the interface method. Expand the BADI Definition name and double click on BADI implementation.

 

 

11. You will be directed to the enhancement implementation screen, shown below. Double click on the Interface method and you will be prompted to create implementation for the method.


 

12. On clicking yes, you will be navigated to editor for the method. Add the following code for showing a message or anything as per your requirement. Save it and activate.

 

 

So the BADI definition and implementation part is complete.

 

Next we will see how we can call this Kernel BADI in our Custom program.

 

13. Create or open an existing program in SE38. Point to the line where you need to add enhancement option. Right click and select Create Option.

 

 

14. Give an Enhancement point or section name and Enhancement spot implementation name. Here I have opted an Enhancement point and have entered Enhancement spot implementation name as ‘ZENH_IMP_TEST’ (which we have created before).

 

 

A new line will be added to the existing code as shown below.


 

15. Then add the below code which is shown in the red box below.

 

 

Apart from Classic BADI’s which are been called by Proxy class cl_exithandler, Kernel BADI’s are called directly with the reference to the BADI definition via GET BADI and CALL BADI statements.  That is one of the reasons why Kernel BADI is faster than classic BADI. Also in Classic BADI, while we call it via cl_exithandler,  we use the reference to the interface rather than BADI definition

 

16. Now activate the program and execute it. When the cursor reaches the enhancement point, where the BADI is called it will trigger all the active implementations of that BADI. Here we have only one implementation and that will be triggered, which shows the below message as we have written in the BADI implementation.

 

 

If the program fails to trigger the BADI implementation, please recheck whether everything associated with it is ‘Activated’ after the creation.

 

Thank You.

Formated Excel using XML for ECC , CRM Transaction launcher and email

$
0
0

Objective: To generate the formatted excel file which can be send or download as per below requirement.

 

1: User should able to download excel file when using GUI and execute in foreground mode.

2: When sending the email in foreground as well as if email is send in with background job.

3:When the ECC transaction is use as transaction launcher in SAP CRM the excel file should get generated same as it is working in SAP ECC, as in case of Transaction launcher it works as web page.

 

Advantage of using XML over OLE: As we can use the OLE method in ABAP to generate formatted excel but its work only in GUI foreground mode, where as we can use ‘xml’ concept in foreground as well as in background jobs for sending email etc.

 

Example:  I have made the transaction in ECC which takes input as Year and display all the dates with weekday and in case of weekly off i.e Saturday and Sunday the background color of the cell will be green.

 

xml1.JPG

If user select the first option ‘Download Excel’ system will generate the excel file, presently I have kept the excel file in temp folder and same I have executed if file save successfully and in case of ‘Send email’ system will send the same file as email attachment.

 

Note :  1:We cannot save the file in any PC folder in background but we can save on app. Server using open data set method.

             2: I have not added the code for email in my example we can check demo program BCS_EXAMPLE_7 to send file as email attachment.

             3: I have made this program by refereeing the existing SDN doc.   

http://wiki.scn.sap.com/wiki/display/Snippets/Formatted+Excel+as+Email+Attachment, I have use same for downloading the file in ECC frontend as well as when same is used in CRM WEB UI as transaction launcher.

              4: For checking this you can upload the attach program in your system and can check the same.

 

Output:

 

xml2.JPG

Find here the attach file of program.

ALV with radio button using OOPS concept in module pool program

$
0
0

Scope :

The purpose of this document is to display radio buttons in ALV grid.

Business requirement :

Consider a scenario where the screen needs to be displayed with a list of accounting document numbers, fiscal year and company code. By Selecting one option at a time, it should navigate to the next screen (FB03) with the corresponding details of that selected accounting document number.

SAP ALV Limitation :

As radio button is nowhere included in as a genuine feature of ALV grid, it is a bit tricky. We can implement the same by using the corresponding ICON and HOTSPOT_CLICK event.

Workaround:

In this case from a report program we are calling screen where ALV Grid is displayed.

In the report program write the below code:

  1. 1. Declaration:

Create a top include in the report program. Add below lines of code:

TYPE-POOLS: slis.

INCLUDE <icon>.

 

Internal table structure:

As mentioned in the scenario with accounting document number, fiscal year and company code, radio button should be get displayed. So in top of program only structure of internal table will be of following type:

 

TYPES:BEGIN OF ty_view,
        bukrs
TYPE bukrs,
        belnr
TYPE belnr_d,
        gjahr
TYPE gjahr,
        radio(4)
TYPE c,
        handle_style 
TYPE lvc_t_styl,
       
END OF ty_view.

Make this field (RADIO) as both hot-spot and be active on double click. Then using the corresponding icons and the HOTSPOT_CLICK event it works like a radio button. For achieving our goal we have to use local class and methods in our report program.

 

Define and implement event handler class

 

Define a local class and declare two methods one for handling hotspot and other one for handling double click.

   

    CLASS lcl_event_handler DEFINITION FINAL.

          PUBLIC SECTION.

          METHODS: handle_double_click  FOR EVENT double_click OF cl_gui_alv_grid

IMPORTING e_row e_column,

                     handle_hotspot_click FOR EVENT hotspot_click OF cl_gui_alv_grid

IMPORTING e_row_id
                                                          e_column_id
                                                    es_row_no
                                                    sender.

     ENDCLASS.                   

 

Write implementation of that class with implementation of the method.

CLASS lcl_event_handler IMPLEMENTATION.

 
METHOD: handle_double_click.
   
CALL METHOD g_grid3->get_selected_rows
     
IMPORTING
        et_index_rows = lt_selected_rows.
 
ENDMETHOD.                   

 

  METHOD: handle_hotspot_click.
   
FIELD-SYMBOLS:<ls_entry> TYPE ty_view,
                             <ld_fld>  
TYPE ANY.
   
LOOP AT gt_view ASSIGNING <ls_entry>.
     
IF sy-tabix EQ es_row_no-row_id.
       
ASSIGN COMPONENT e_column_id-fieldname OF STRUCTURE <ls_entry>
       
TO <ld_fld>.
       
IF ( <ld_fld> IS ASSIGNED ). * Set selected radio button "selected".
          <ld_fld> = icon_radiobutton.
       
ENDIF.
     
ELSE.

 

  1. Module Pool:

            Open the screen where ALV grid with radio button needs to be displayed (For example screen number is 1000) and create a custom control in that. Suppose the name of the custom control is C_CUST_CONT3.

 

custom control.jpg

 

PBO

  1. Now in PBO of module pool program. Our aim to display ALV grid with radio button in screen.

  Structure of field catalog and layout will be of type: lvc_t_fcat and lvc_s_layo. 

Initialy ALV will be displayed with one radio button as set.

So for setting a radio button we can just by default set 1st row as set.

Gf_view-radio = icon_radiobutton.  “It will tell selected radio button.

And for other entries set them as unselected for that pass

gf_view-radio = icon_wd_radio_button_empty.

 

  1. While building fieldcatalog for that radio field we have to pass below 2 fields :

  gf_fieldcat1-icon       = 'X'.

gf_fieldcat1-hotspot = 'X'.

  1. While creating layout of the ALV table we need to pass stylefname with:

  gf_lay-stylefname = 'HANDLE_STYLE'. 

  1. To handle events we have to create event handler.

CREATE OBJECT go_handler .
   
SET HANDLER:

    go_handler->handle_double_click  FOR g_grid3,
    go_handler->handle_hotspot_click
FOR g_grid3.

    CALL METHOD cl_gui_control=>set_focus
     
EXPORTING
       
control = g_grid3.

 

 

To display output:

*-To display output.
   
CALL METHOD g_grid3->set_table_for_first_display
     
EXPORTING
        is_layout                     = gf_lay
     
CHANGING
        it_outtab                     = gt_view
        it_fieldcatalog               = gt_fieldcat1
     
EXCEPTIONS
        invalid_parameter_combination =
1
        program_error                 =
2
        too_many_lines                =
3
       
OTHERS                        = 4.

 

If it is not for first time then we need to check change data and refresh ALV data

          CALL METHOD g_grid3->check_changed_data.
         
CALL METHOD g_grid3->refresh_table_display.

         
CALL METHOD cl_gui_control=>set_focus
         
EXPORTING
         
control = g_grid3.

 

PAI :

The below code has to be written for ‘REFRESH’ OKCODE.

Refresh table display after switching the radiobuttons

  DATA: ls_stable TYPE lvc_s_stbl.
  ls_stable-row = abap_true.
  ls_stable-col = abap_true.

 

  CALL METHOD g_grid3->refresh_table_display
   
EXPORTING
      is_stable = ls_stable
   
EXCEPTIONS
      finished  =
1
     
OTHERS    = 2.


  gx_fresh =

'X'.

 

In PAI of the screen read internal table where for field radio button icon is set like

READ TABLE gt_view INTO gf_view WITH KEY radio = icon_radiobutton.

After that call transaction FB03 and skip first screen.

 

The screen will look as below:

output screen1.jpg

 

output screen 2.jpg

The screen navigates to the accounting document screen transaction FB03.

tcode FB03.jpg

 

Conclusion: Thus the radio buttons could be included in ALV grid display using ICON and HOTSPOT_CLICK event.

The case of statics

$
0
0
Hi all,
There are occasions where we have a code that looks like this:

FORM loop_with_select .

  DATA: t01 TYPE i ,
        t02 TYPE i ,
        dif TYPE i .

  DATA: it_sflight TYPE TABLE OF sflight .
  FIELD-SYMBOLS: <st_sflight> LIKE LINE OF it_sflight .

  DATA: st_scarr TYPE scarr .

  SELECT * FROM sflight INTO TABLE it_sflight .

  SORT it_sflight BY fldate .

  GET RUN TIME FIELD t01.

  LOOP AT it_sflight ASSIGNING <st_sflight> .

* For each row we go and select a record from scarr
    SELECT SINGLE * INTO st_scarr
      FROM scarr
      WHERE carrid EQ <st_sflight>-carrid.

  ENDLOOP .

  GET RUN TIME FIELD t02 . dif = t02 - t01.

  WRITE: / 'loop_with_select:' , dif .

ENDFORM .                    "loop_with_select

We have a loop and within the loop we execute some select single to get some extra data (e.g. text).

 

 

This raise a performance problem .

 

 

One solution is to implement a cache service in the program. The STATICS declaration allow us to create a form for that purpose .

FORM get_cache_data
  USING
    carrid   TYPE scarr-carrid
  CHANGING
    st_scarr TYPE scarr .

  CLEAR st_scarr .

* Use static variable as cache
  STATICS: it_scarr TYPE HASHED TABLE OF scarr
  WITH UNIQUE KEY
    carrid .

* Try the cache .
  READ TABLE it_scarr INTO st_scarr
  WITH TABLE KEY
    carrid = carrid .

  CHECK sy-subrc NE 0 .

  st_scarr-carrid = carrid .

  SELECT SINGLE * INTO st_scarr
  FROM scarr
  WHERE
    carrid EQ carrid .

* We insert the result of the select always so we have
* empty description in those cases where there is no data in scarr for given "carrid"
  INSERT st_scarr INTO TABLE it_scarr .

ENDFORM .                    "get_cache_data

Lets use FORM get_cache_data:

FORM loop_with_cache .

  DATA: t01 TYPE i ,
        t02 TYPE i ,
        dif TYPE i .

  DATA: it_sflight TYPE TABLE OF sflight .
  FIELD-SYMBOLS: <st_sflight> LIKE LINE OF it_sflight .

  DATA: st_scarr TYPE scarr .

  SELECT * FROM sflight INTO TABLE it_sflight .

  SORT it_sflight BY fldate .

  GET RUN TIME FIELD t01.

  LOOP AT it_sflight ASSIGNING <st_sflight> .

* For each row we go and ask for a record from the cache
    PERFORM get_cache_data
     USING
       <st_sflight>-carrid
    CHANGING
       st_scarr .

  ENDLOOP .

  GET RUN TIME FIELD t02 . dif = t02 - t01.

  WRITE: / 'loop_with_cache:' , dif .

ENDFORM .                    "loop_with_cache

 

Pros:

  • No change in program logic.
  • Performance boost (IT_SFLIGHT contain about 400 entries )

Clipboard01.jpg

Cons:

  • Higher memory requirement .
  • Extra code.

Notes:


SAP use functions for this purpose (Use SE37 and search for *SINGLE*READ* )  but some times it is better to create your own.

 

Happy coding.


Integer Arithmetic Operations on Large Numbers

$
0
0

Maximum positive value that can be stored by integer type variable in ABAP is 2147483647.

For values beyond maximum limit of integer variable, workarounds can be used.

One such example is discussion MOD operation fail for large numbers started by Starlet Abraham

I was able to calculate correct result of 512^17 MOD 2773 using the methods detailed below.

 

I have written this program to do following operations on large integers.

  • Addition
  • Subtraction
  • Multiplication
  • Division
  • Mod
  • Power

 

Full code snippet is posted at the end of this document.

Program has its flaws, but it works.

I would briefly go through how the logic works.

 

How are big numbers stored?

Local class lcl_bignum has instance attributes that store big numbers.

LV_STRING - Number stored as string type.

LT_INT - an internal table of integers. The string is broken into substrings of size 4 (base 10000), and those substrings ( as int4 ) are stored in internal table.

LV_SIGN - integer type to store the sign of number. +1 for positive, -1 for negative.

For example, number 1234567890 will be stored in internal table as

 

LT_INT
7890
3456
12

 

 

 

Why is number broken into base 10000?

Base 10000 is safe considering the capacity of integer variable type in ABAP.

Computing 9999 * 9999 results in 99980001, which is within the limits of integer type.

On the other hand, 99999 * 99999 results in 999980001, which would lead to overflow exception.

 

How to create instance and store big number?

Below code snippets can be used to create instance of big number.

The constructor parameters are options.

CREATE OBJECT lr3.

 

--

Above code will create instance with zero value in it.

 

CREATE OBJECT lr2
  EXPORTING
    i_value = '533335555511111'.

--

Above code will create instance and populate lv_string and lt_int by breaking down input string.

Sign of number is positive by default.

Input string should have only numbers in it.

 

CREATE OBJECT lr1
  EXPORTING
    i_value = '6584389034291301828999'
    i_negative = 'X'.

--

Using above code, 'X' can be passed i_negative flag if we have a negative number.

 

How to add numbers?

Instance method Add( ) can be used for adding numbers.

It accepts 2 object reference that need to be added, and result is stored in object whose method gets called.

We are adding the numbers starting lowest weightage (LT_INT[1]), and carrying forward extra in case of overflow.

For example, we add 12345678 and 22223333. Program would add (5678,3333) first, and then (1234,2222).

For A = B + C, below code can be used.

 

lr3->add( i_obj1 = lr1
          i_obj2 = lr2 ).

--

For A = A + B, below code can be used.

 

lr3->add( i_obj1 = lr3
          i_obj2 = lr2 ).

--

 

How to subtract numbers?

Instance method Subtract( ) can be used for subtracting numbers.

The usage is same as Add( ) method.

 

Looking at code, you would see that Add( ) and Subtract( ) are calling each other.

It is done the tackle how absolute values are treated depending on their sign.

For example, A = B + C, the values of B and C will be added, and common sign will be retained if B and C have same sign. Both positive, or both negative.

If the signs of B and C are different, we essentially have to keep sign of B, and calculate |B| - |C| (absolute values).

 

How to multiply numbers?

Instance method Multiply( ) can be used.

It accepts 2 object references, and stores result in calling object.

I would explain the logic using example. It is similar to the method used in elementary school.

For elementary example of multiplying 123 and 456, below logic is used.

123

456

===

3*6 + (3*5+2*6) + (3*4+2*5+1*6) + (2*4+1*5) + 1*4

Same thing is done in program at base 10000 level.

At every stage we are carrying forward the overflow value.

 

How to divide numbers?

For division, I am guessing the answer by multiplying.

Something like binary search, I start with 1 as answer, keep on multiplying it by 10000 still answer crosses dividend.

Once the guess surpasses dividend, I take a step back, and start multiplying by square root of 10000.

A point comes when multiplier is reduced to 1, and multiplication can no longer be used to get closer to answer.

I then use addition to get closer to answer. Instead of square root, divide by 2 to get next "jump value".

A dry run using elementary example would be something like this.

451

4

---

 

How to do calculate remainder (MOD operation)

Instance method Mod( ) can be used, which internally uses Divide( ), Multiply( ) and Subtract( ).

To calculate A = B MOD C, program does something like:

A = B - C * ( B DIV C )

Here we are reusing the code written in previous methods.

 

How to calculate Power?

Instance method Power( ) can be used, which internally uses Multiply( ) and Subtract( ).

For calculating A = B POWER C, program starts with 1 as answer, uses loop to multiply B to answer, C number of times.

 

Full code snippet

  1. *----------------------------------------------------------------------*
  2. *       CLASS lcl_bignum DEFINITION
  3. *----------------------------------------------------------------------*
  4. *
  5. *----------------------------------------------------------------------*
  6. CLASS lcl_bignum DEFINITION.
  7.   PUBLIC SECTION.
  8.     METHODS constructor IMPORTING i_value TYPE string OPTIONAL
  9.                                   i_negative  TYPE c OPTIONAL.
  10.     METHODS get_sign RETURNING value(r_sign) TYPE i.
  11.     METHODS get_string RETURNING value(r_string) TYPE string.
  12.     METHODS get_int RETURNING value(r_int) TYPE int4_table.
  13.     METHODS set_data IMPORTING i_value TYPE string
  14.                                i_negative TYPE c OPTIONAL.
  15.     METHODS add IMPORTING i_obj1 TYPE REF TO lcl_bignum
  16.                           i_obj2 TYPE REF TO lcl_bignum.
  17.     METHODS subtract IMPORTING  i_obj1 TYPE REF TO lcl_bignum
  18.                                 i_obj2 TYPE REF TO lcl_bignum.
  19.     METHODS multiply IMPORTING  i_obj1 TYPE REF TO lcl_bignum
  20.                                 i_obj2 TYPE REF TO lcl_bignum.
  21.     METHODS divide IMPORTING i_obj1 TYPE REF TO lcl_bignum
  22.                              i_obj2 TYPE REF TO lcl_bignum.
  23.     METHODS mod IMPORTING i_obj1 TYPE REF TO lcl_bignum
  24.                           i_obj2 TYPE REF TO lcl_bignum.
  25.     METHODS power IMPORTING i_obj1 TYPE REF TO lcl_bignum
  26.                             i_obj2 TYPE REF TO lcl_bignum.
  27.     METHODS invert_sign.
  28.     METHODS copy_values IMPORTING i_obj TYPE REF TO lcl_bignum.
  29.     METHODS abs_compare IMPORTING i_obj TYPE REF TO lcl_bignum
  30.                         RETURNING value(r_result) TYPE i.
  31.   PROTECTED SECTION.
  32.     METHODS int_to_string.
  33.     METHODS split_into_int.
  34.     METHODS delete_leading_zeros.
  35.     METHODS divide_by_2.
  36.   PRIVATE SECTION.
  37.     DATA lv_string TYPE string.
  38.     DATA lv_sign TYPE i VALUE 1.
  39.     DATA lt_int TYPE int4_table.
  40.     "sqrt of max int4 is 46340
  41.     CONSTANTS: gc_unit_size TYPE i VALUE 10000,
  42.                gc_unit_digits TYPE i VALUE 4,
  43.                gc_gt TYPE i VALUE 1"greater than
  44.                gc_lt TYPE i VALUE 2"less than
  45.                gc_eq TYPE i VALUE 0"equals
  46. ENDCLASS.                    "lcl_bignum DEFINITION
  47. *----------------------------------------------------------------------*
  48. *       CLASS lcl_bignum IMPLEMENTATION
  49. *----------------------------------------------------------------------*
  50. *
  51. *----------------------------------------------------------------------*
  52. CLASS lcl_bignum IMPLEMENTATION.
  53.   METHOD constructor.
  54.     IF i_value IS SUPPLIED.
  55.       IF i_value CO ' 1234567890'.
  56.         lv_string = i_value.
  57.         CONDENSE lv_string.
  58.       ENDIF.
  59.       split_into_int( ).
  60.     ENDIF.
  61.     IF i_negative IS SUPPLIED.
  62.       IF i_negative EQ 'X'.
  63.         lv_sign = -1.
  64.       ENDIF.
  65.     ENDIF.
  66.   ENDMETHOD.                    "constructor
  67.   METHOD set_data.
  68.     CLEAR: lv_string, lt_int.
  69.     lv_sign = 1.
  70.     IF i_value CO ' 1234567890'.
  71.       lv_string = i_value.
  72.       CONDENSE lv_string.
  73.     ENDIF.
  74.     split_into_int( ).
  75.     IF i_negative IS SUPPLIED.
  76.       IF i_negative EQ 'X'.
  77.         lv_sign = -1.
  78.       ENDIF.
  79.     ENDIF.
  80.   ENDMETHOD.                    "set_data
  81.   METHOD split_into_int.
  82.     DATA lv_string TYPE string.
  83.     DATA lv_int TYPE i.
  84.     lv_string = me->lv_string.
  85.     WHILE lv_string IS NOT INITIAL.
  86.       IF strlen( lv_string ) GT gc_unit_digits.
  87.         SHIFT lv_string RIGHT BY gc_unit_digits PLACES CIRCULAR.
  88.         lv_int = lv_string+0(gc_unit_digits).
  89.         SHIFT lv_string LEFT BY gc_unit_digits PLACES.
  90.       ELSE.
  91.         lv_int = lv_string.
  92.         CLEAR lv_string.
  93.       ENDIF.
  94. *      INSERT lv_int INTO lt_int INDEX 1.
  95.       APPEND lv_int TO lt_int.
  96.     ENDWHILE.
  97.   ENDMETHOD.                    "split_into_int
  98.   METHOD delete_leading_zeros.
  99.     DATA: lt_temp TYPE int4_table,
  100.           lv_temp TYPE i,
  101.           lv_count TYPE i.
  102.     CHECK lt_int IS NOT INITIAL.
  103.     lt_temp = lt_int.
  104.     CLEAR lt_int.
  105.     lv_count = lines( lt_temp ).
  106.     DO lv_count TIMES.
  107.       READ TABLE lt_temp INTO lv_temp INDEX lv_count.
  108.       IF lv_temp IS NOT INITIAL.
  109.         EXIT.
  110.       ENDIF.
  111.       lv_count = lv_count - 1.
  112.     ENDDO.
  113.     IF lv_count IS NOT INITIAL AND
  114.        lv_count LE lines( lt_temp ).
  115.       APPEND LINES OF lt_temp FROM 1 TO lv_count TO lt_int.
  116.     ENDIF.
  117.   ENDMETHOD.                    "delete_leading_zeros
  118.   METHOD int_to_string.
  119.     DATA lv_int TYPE i.
  120.     DATA lv_char TYPE n LENGTH gc_unit_digits.
  121.     LOOP AT lt_int INTO lv_int.
  122.       lv_char = lv_int.
  123.       CONCATENATE lv_char lv_string INTO lv_string.
  124.     ENDLOOP.
  125.     SHIFT lv_string LEFT DELETING LEADING '0'.
  126.   ENDMETHOD.                    "int_to_string
  127.   METHOD get_int.
  128.     r_int = lt_int.
  129.   ENDMETHOD.                    "get_int
  130.   METHOD get_sign.
  131.     r_sign = lv_sign.
  132.   ENDMETHOD.                    "get_sign
  133.   METHOD get_string.
  134.     r_string = lv_string.
  135.   ENDMETHOD.                    "get_string
  136.   METHOD copy_values.
  137.     lv_string = i_obj->get_string( ).
  138.     lv_sign = i_obj->get_sign( ).
  139.     lt_int = i_obj->get_int( ).
  140.   ENDMETHOD.                    "copy_values
  141.   METHOD abs_compare.
  142.     DATA: lt_int2 TYPE int4_table,
  143.           lv_int TYPE i,
  144.           lv_int2 TYPE i,
  145.           lv_max TYPE i.
  146.     lt_int2 = i_obj->get_int( ).
  147.     lv_max = lines( lt_int ).
  148.     IF lines( lt_int2 ) GT lv_max.
  149.       lv_max = lines( lt_int2 ).
  150.     ENDIF.
  151.     WHILE lv_max GT 0.
  152.       CLEAR: lv_int,
  153.              lv_int2.
  154.       READ TABLE lt_int INTO lv_int INDEX lv_max.
  155.       READ TABLE lt_int2 INTO lv_int2 INDEX lv_max.
  156.       IF lv_int EQ lv_int2.
  157.         lv_max = lv_max - 1.
  158.       ELSE.
  159.         IF lv_int GT lv_int2.
  160.           r_result = gc_gt.
  161.         ELSEIF lv_int LT lv_int2.
  162.           r_result = gc_lt.
  163.         ENDIF.
  164.         EXIT.
  165.       ENDIF.
  166.     ENDWHILE.
  167.   ENDMETHOD.                    "abs_compare
  168.   METHOD divide_by_2.
  169.     DATA: lv_int TYPE i,
  170.           lt_temp TYPE int4_table,
  171.           lv_mod TYPE i,
  172.           lv_count TYPE i.
  173.     lv_count = lines( lt_int ).
  174.     DO lv_count TIMES.
  175.       READ TABLE lt_int INTO lv_int INDEX lv_count.
  176.       IF sy-subrc EQ 0.
  177.         lv_int = lv_int + lv_mod * gc_unit_size.
  178.         lv_mod = lv_int MOD 2.
  179.         lv_int = lv_int DIV 2.
  180.         INSERT lv_int INTO lt_temp INDEX 1.
  181.       ENDIF.
  182.       lv_count = lv_count - 1.
  183.     ENDDO.
  184.     lt_int = lt_temp.
  185.     delete_leading_zeros( ).
  186.     int_to_string( ).
  187.   ENDMETHOD.                    "divide_by_2
  188.   METHOD invert_sign.
  189.     lv_sign = lv_sign * -1.
  190.   ENDMETHOD.                    "invert_sign
  191.   METHOD add.
  192.     DATA: lt_int1 TYPE int4_table,
  193.           lt_int2 TYPE int4_table,
  194.           lv_int TYPE i,
  195.           lv_int1 TYPE i,
  196.           lv_int2 TYPE i,
  197.           lv_index TYPE i,
  198.           lv_count TYPE i,
  199.           lv_extra TYPE i.
  200.     lt_int1 = i_obj1->get_int( ).
  201.     lt_int2 = i_obj2->get_int( ).
  202.     IF i_obj1->get_sign( ) NE i_obj2->get_sign( ).
  203.       subtract( i_obj1 = i_obj1
  204.                 i_obj2 = i_obj2 ).
  205.       EXIT.
  206.     ENDIF.
  207.     lv_count = lines( lt_int1 ).
  208.     IF lv_count LT lines( lt_int2 ).
  209.       lv_count = lines( lt_int2 ).
  210.     ENDIF.
  211.     CLEAR: lt_int, lv_string.
  212.     lv_sign = i_obj1->get_sign( ).
  213.     DO lv_count TIMES.
  214.       CLEAR: lv_int1,
  215.              lv_int2.
  216.       lv_index = sy-index.
  217.       READ TABLE lt_int1 INTO lv_int1 INDEX lv_index.
  218.       READ TABLE lt_int2 INTO lv_int2 INDEX lv_index.
  219.       lv_int = lv_extra + lv_int1 + lv_int2.
  220.       lv_extra = lv_int DIV gc_unit_size.
  221.       lv_int = lv_int MOD gc_unit_size.
  222.       APPEND lv_int TO lt_int.
  223.     ENDDO.
  224.     int_to_string( ).
  225.   ENDMETHOD.                    "add
  226.   METHOD subtract.
  227.     DATA: lt_int1 TYPE int4_table,
  228.           lt_int2 TYPE int4_table,
  229.           lv_int TYPE i,
  230.           lv_int1 TYPE i,
  231.           lv_int2 TYPE i,
  232.           lv_index TYPE i,
  233.           lv_count TYPE i,
  234.           lv_extra TYPE i.
  235.     FIELD-SYMBOLS: <fs_int> TYPE i.
  236.     lt_int1 = i_obj1->get_int( ).
  237.     lt_int2 = i_obj2->get_int( ).
  238.     IF i_obj1->get_sign( ) NE i_obj2->get_sign( ).
  239.       i_obj2->invert_sign( ).
  240.       add( i_obj1 = i_obj1
  241.            i_obj2 = i_obj2 ).
  242.       EXIT.
  243.     ENDIF.
  244.     lv_count = lines( lt_int1 ).
  245.     IF lv_count LT lines( lt_int2 ).
  246.       lv_count = lines( lt_int2 ).
  247.     ENDIF.
  248.     CLEAR: lt_int, lv_string.
  249.     lv_sign = i_obj1->get_sign( ).
  250.     DO lv_count TIMES.
  251.       CLEAR: lv_int1,
  252.              lv_int2.
  253.       lv_index = sy-index.
  254.       READ TABLE lt_int1 INTO lv_int1 INDEX lv_index.
  255.       READ TABLE lt_int2 INTO lv_int2 INDEX lv_index.
  256.       lv_int = lv_extra + lv_int1 - lv_int2.
  257.       CLEAR lv_extra.
  258.       IF lv_int LT 0.
  259.         lv_int = lv_int + gc_unit_size.
  260.         lv_extra = -1.
  261.       ENDIF.
  262.       lv_int = lv_int MOD gc_unit_size.
  263.       APPEND lv_int TO lt_int.
  264.     ENDDO.
  265.     IF lv_extra IS NOT INITIAL.
  266.       lv_sign = lv_sign * lv_extra.
  267.       LOOP AT lt_int ASSIGNING <fs_int>.
  268.         IF sy-tabix EQ 1.
  269.           <fs_int> = gc_unit_size - <fs_int>.
  270.         ELSE.
  271.           <fs_int> = gc_unit_size - <fs_int> + 1.
  272.         ENDIF.
  273.       ENDLOOP.
  274.     ENDIF.
  275.     delete_leading_zeros( ).
  276.     int_to_string( ).
  277.   ENDMETHOD.                    "subtract
  278.   METHOD multiply.
  279.     DATA: lt_int1 TYPE int4_table,
  280.           lt_int2 TYPE int4_table,
  281.           lv_int TYPE i,
  282.           lv_int1 TYPE i,
  283.           lv_int2 TYPE i,
  284.           lv_int_tmp TYPE i,
  285.           lv_index TYPE i,
  286.           lv_index_start TYPE i,
  287.           lv_index_end   TYPE i,
  288.           lv_index_start_tmp TYPE i,
  289.           lv_index_end_tmp TYPE i,
  290.           lv_count TYPE i,
  291.           lv_carry TYPE i,
  292.           lv_extra TYPE i.
  293.     lt_int1 = i_obj1->get_int( ).
  294.     lt_int2 = i_obj2->get_int( ).
  295.     lv_count = lines( lt_int1 ).
  296.     IF lv_count LT lines( lt_int2 ).
  297.       lv_count = lines( lt_int2 ).
  298.     ENDIF.
  299.     CLEAR: lt_int, lv_string.
  300.     lv_sign = i_obj1->get_sign( ) * i_obj2->get_sign( ).
  301.     CHECK lv_count IS NOT INITIAL.
  302.     lv_index_start = 1.
  303.     lv_index_end   = 1.
  304.     DO.
  305.       CLEAR lv_int.
  306.       lv_index_start_tmp = lv_index_start.
  307.       lv_index_end_tmp   = lv_index_end.
  308.       lv_int = lv_extra.
  309.       CLEAR lv_extra.
  310.       WHILE lv_index_start_tmp LE lv_index_end.
  311.         CLEAR: lv_int1,
  312.                lv_int2.
  313.         READ TABLE lt_int1 INTO lv_int1 INDEX lv_index_start_tmp.
  314.         READ TABLE lt_int2 INTO lv_int2 INDEX lv_index_end_tmp.
  315.         lv_int_tmp = ( lv_int1 * lv_int2 ) MOD gc_unit_size.
  316.         lv_extra = lv_extra + ( lv_int1 * lv_int2 ) DIV gc_unit_size.
  317.         lv_int = lv_int + lv_int_tmp.
  318.         lv_extra = lv_extra + lv_int DIV gc_unit_size.
  319.         lv_int = lv_int MOD gc_unit_size.
  320.         lv_index_start_tmp = lv_index_start_tmp + 1.
  321.         lv_index_end_tmp = lv_index_end_tmp - 1.
  322.       ENDWHILE.
  323.       APPEND lv_int TO lt_int.
  324.       IF lv_index_end LT lv_count.
  325.         lv_index_end = lv_index_end + 1.
  326.       ELSEIF lv_index_start LT lv_count.
  327.         lv_index_start = lv_index_start + 1.
  328.       ELSEIF lv_index_start EQ lv_count AND
  329.          lv_index_end   EQ lv_count.
  330.         EXIT.
  331.       ENDIF.
  332.     ENDDO.
  333.     IF lv_extra IS NOT INITIAL.
  334.       APPEND lv_extra TO lt_int.
  335.     ENDIF.
  336.     delete_leading_zeros( ).
  337.     int_to_string( ).
  338.   ENDMETHOD.                    "multiply
  339.   METHOD divide.
  340.     DATA: lt_int1 TYPE int4_table,
  341.           lt_int2 TYPE int4_table,
  342.           lv_int TYPE i,
  343.           lv_int1 TYPE i,
  344.           lv_int2 TYPE i,
  345.           lv_string1 TYPE string,
  346.           lv_string2 TYPE string,
  347.           lv_index TYPE i,
  348.           lv_count TYPE i,
  349.           lv_extra TYPE i,
  350.           lv_sign1 TYPE i,
  351.           lr1 TYPE REF TO lcl_bignum,
  352.           lr2 TYPE REF TO lcl_bignum,
  353.           lr_guess TYPE REF TO lcl_bignum,
  354.           lr_step TYPE REF TO lcl_bignum,
  355.           lv_step_str TYPE string,
  356.           lv_step TYPE i,
  357.           lr_temp  TYPE REF TO lcl_bignum.
  358.     CREATE OBJECT lr1.
  359.     CREATE OBJECT lr2.
  360.     lr1->copy_values( i_obj1 ).
  361.     lr2->copy_values( i_obj2 ).
  362. *   quotient is zero when divisor is bigger than dividend
  363.     CHECK lr1->abs_compare( lr2 ) EQ gc_gt.
  364.     IF lr1->get_sign( ) LT 0.
  365.       lr1->invert_sign( ).
  366.     ENDIF.
  367.     IF lr2->get_sign( ) LT 0.
  368.       lr2->invert_sign( ).
  369.     ENDIF.
  370. * start with 1, keep multiplying by gc_unit_size
  371.     CREATE OBJECT lr_guess
  372.       EXPORTING
  373.         i_value = '1'.
  374.     CREATE OBJECT lr_temp.
  375.     CREATE OBJECT lr_step.
  376.     lv_step = gc_unit_size.
  377.     DO.
  378.       DO.
  379.         lr_temp->multiply( i_obj1 = lr_guess
  380.                            i_obj2 = lr2 ).
  381.         CASE lr_temp->abs_compare( lr1 ).
  382.           WHEN gc_eq.
  383.             copy_values( lr_guess ).
  384.             RETURN.
  385.           WHEN gc_gt.
  386.             EXIT.
  387.           WHEN gc_lt.
  388. * increment
  389. *            lv_step = gc_unit_size.
  390.             copy_values( lr_guess ).
  391.             lv_step_str = lv_step.
  392.             lr_step->set_data( lv_step_str ).
  393.             lr_guess->multiply( i_obj1 = lr_guess
  394.                                 i_obj2 = lr_step ).
  395. *        when others.
  396.         ENDCASE.
  397.       ENDDO.
  398.       lr_guess->copy_values( me ).
  399.       lv_step = sqrt( lv_step ).
  400.       IF lv_step EQ 1.
  401.         EXIT.
  402.       ENDIF.
  403.     ENDDO.
  404. * answer is between guess and guess * 2
  405. * now add steps to move closer to answer
  406. *    lv_step = gc_unit_size.
  407.     lr_step->copy_values( lr_guess ).
  408.     DO.
  409.       DO.
  410.         lr_temp->multiply( i_obj1 = lr_guess
  411.                            i_obj2 = lr2 ).
  412.         CASE lr_temp->abs_compare( lr1 ).
  413.           WHEN gc_eq.
  414.             copy_values( lr_guess ).
  415.             RETURN.
  416.           WHEN gc_gt.
  417.             EXIT.
  418.           WHEN gc_lt.
  419. * increment
  420.             copy_values( lr_guess ).
  421.             lr_guess->add( i_obj1 = lr_guess
  422.                            i_obj2 = lr_step ).
  423. *        when others.
  424.         ENDCASE.
  425.       ENDDO.
  426.       lr_guess->copy_values( me ).
  427. * quick way to divide by 2
  428.       lr_step->divide_by_2( ).
  429.       IF lr_step->get_int( ) IS INITIAL.
  430.         EXIT.
  431.       ENDIF.
  432.     ENDDO.
  433. *    int_to_string( ).
  434.   ENDMETHOD.                    "divide
  435.   METHOD mod.
  436.     DATA lr_div TYPE REF TO lcl_bignum.
  437.     CREATE OBJECT lr_div.
  438.     lr_div->divide( i_obj1 = i_obj1
  439.                     i_obj2 = i_obj2 ).
  440.     lr_div->multiply( i_obj1 = lr_div
  441.                       i_obj2 = i_obj2 ).
  442.     subtract( i_obj1 = i_obj1
  443.               i_obj2 = lr_div ).
  444.   ENDMETHOD.                    "mod
  445.   METHOD power.
  446.     DATA: lr_power TYPE REF TO lcl_bignum,
  447.           lr_one   TYPE REF TO lcl_bignum.
  448.     CREATE OBJECT lr_one
  449.       EXPORTING
  450.         i_value = '1'.
  451.     CREATE OBJECT lr_power.
  452.     lr_power->copy_values( i_obj2 ).
  453. * only positive power
  454.     IF get_sign( ) NE lr_power->get_sign( ).
  455.       lr_power->invert_sign( ).
  456.     ENDIF.
  457. * result 1 when power is 0
  458.     set_data( '1' ).
  459.     DO.
  460.       IF lr_power->get_int( ) IS INITIAL.
  461.         EXIT.
  462.       ELSE.
  463.         lr_power->subtract( i_obj1 = lr_power
  464.                             i_obj2 = lr_one ).
  465.         multiply( i_obj1 = me
  466.                   i_obj2 = i_obj1 ).
  467.       ENDIF.
  468.     ENDDO.
  469.   ENDMETHOD.                    "power
  470. ENDCLASS.                    "lcl_bignum IMPLEMENTATION
  471. START-OF-SELECTION.
  472.   DATA lr1 TYPE REF TO lcl_bignum.
  473.   DATA lr2 TYPE REF TO lcl_bignum.
  474.   DATA lr3 TYPE REF TO lcl_bignum.
  475.   TRY .
  476.       CREATE OBJECT lr1
  477.         EXPORTING
  478.           i_value = '6584389034291301828999'.
  479. *          i_negative = 'X'.
  480.       CREATE OBJECT lr2
  481.         EXPORTING
  482.           i_value = '533335555511111'.
  483.       CREATE OBJECT lr3.
  484.       lr3->add( i_obj1 = lr1
  485.                 i_obj2 = lr2 ).
  486. *     lr3->subtract( i_obj1 = lr1
  487. *                    i_obj2 = lr2 ).
  488. *     lr3->multiply( i_obj1 = lr1
  489. *                    i_obj2 = lr2 ).
  490. *     lr3->divide( i_obj1 = lr1
  491. *                  i_obj2 = lr2 ).
  492. *     lr3->mod( i_obj1 = lr1
  493. *               i_obj2 = lr2 ).
  494.       lr1->set_data( '512' ).
  495.       lr2->set_data( '17' ).
  496.       lr3->power( i_obj1 = lr1
  497.                   i_obj2 = lr2 ).
  498.       lr2->set_data( '2773' ).
  499.       lr3->mod( i_obj1 = lr3
  500.                 i_obj2 = lr2 ).
  501.     CATCH cx_root.
  502.   ENDTRY.

Handling Customer Fields in BAPIs which doesn't have Extension Structure

$
0
0

Handling Customer Fields in BAPIs which doesn't have Extension Structure

 

Scenario:

        You have identified a BAPI for a certain SAP process creation, the standard SAP Process has customer fields to be filled in too. But the BAPI doesn’t have an extension structure to update the Customer Fields involved in it. And your client mandates against the use of BDC.

 

Illustration:

     As an example the BAPI to create a Notification BAPI_ALM_NOTIF_CREATE (which doesn’t have an extension structure), equivalent to the transaction IW21, is considered.

 

     The QMEL structure has been enhanced with an Append Structure with custom fields in it.

 

Img1.jpg

 

IW21 is configured such that the added customer fields are linked to the VIQMEL structure (QMEL’s View).

 

Img2.jpg

 

     In this case there is no direct approach to fill in the customer field data into the BAPI BAPI_ALM_NOTIF_CREATE, as it doesn’t have the QMEL structure in the either the import or the table parameters.

 

     To address these scenarios SAP has been providing Customer Exits which could handle the Structures which hold the Customer fields to be update in the Standard Transaction.

 

     In our scenario, analyzing the flow of the BAPI BAPI_ALM_NOTIF_CREATE, lead to identify a customer exit QQMA0025 with the exit FM EXIT_SAPLIQS0_017 which handles the structure VIMEL in the importing and

exporting parameters as below

 

Img3.jpg

 

So in order to solve this scenario, follow the below steps,

·         -->Implement the customer exit which is identified to handle the customized structure (VIQMEL in our case)

 

·         -->In the source program where in the BAPI BAPI_ALM_NOTIF_CREATE is used to create a Notification,EXPORT the customer data in to Memory ID.

 

·         -->In the implemented customer exit, IMPORT the Customer Field data from the Memory ID.

 

·         -->Fill the imported data to the corresponding fields of the VIQMEL structure.

 

This approach will help us in preventing the issues which could arise in implementing a BDC call for such scenarios. BDC calls are prone to issue relating to the Changes in Screen Configuration and Enhancement Pack related changes.

Multi Sales Deal Terms in VB21 (Dialog Box for Overlapping Dates)

$
0
0

Hi,

 

sometimes you must implement modification for multi sales deal terms in VB21 by screen 123 (Dialog Box for Overlapping Dates) off.

 

So You must modify 2 programs:

 

  1. 1.  MV13AF0G

 

*----------------------------------------------------------------------*

*       FORM  GUELTIGKEIT_PRUEFEN_AGREEMENT                            *

*----------------------------------------------------------------------*

*       The validity periods for condition records in sales deals may  *

*       not overlap in any way with condition records with the same    *

*       condition type and variable key but on a different agreement.  *

*----------------------------------------------------------------------*

FORM gueltigkeit_pruefen_verkaufsak USING all

                                          sichern

                                 CHANGING value(gp_subrc).

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""$"$\SE:(1) Form GUELTIGKEIT_PRUEFEN_VERKAUFSAK, Start A

*$*$-Start: (1)---------------------------------------------------------------------------------$*$*

ENHANCEMENT 1  Z_MV13AFOG.    "active version

DATA: BEGIN OF S_KNUMH OCCURS 0,

        KNUMH TYPE KNUMH,

        datab TYPE kodatab,

        datbi TYPE kodatbi,

        ANSWER,

      END OF S_KNUMH.

 

 

IF sy-ucomm = 'SICH'.

   IMPORT s_knumh TO s_knumh FROM MEMORY ID 'KNUMH'.

ENDIF.

 

RANGES s_ucomm FOR sy-ucomm.

 

s_ucomm-sign = 'I'.

s_ucomm-option = 'EQ'.

s_ucomm-low = 'SICH'.

APPEND s_ucomm.

 

s_ucomm-sign = 'I'.

s_ucomm-option = 'EQ'.

s_ucomm-low = 'ABRE'.

APPEND s_ucomm.

 

s_ucomm-sign = 'I'.

s_ucomm-option = 'EQ'.

s_ucomm-low = 'SIC1'.

APPEND s_ucomm.

 

s_ucomm-sign = 'I'.

s_ucomm-option = 'EQ'.

s_ucomm-low = 'OPT1'.

APPEND s_ucomm.

 

s_ucomm-sign = 'I'.

s_ucomm-option = 'EQ'.

s_ucomm-low = 'ENT1'.

APPEND s_ucomm.

 

s_ucomm-sign = 'I'.

s_ucomm-option = 'EQ'.

s_ucomm-low = 'OPT1'.

APPEND s_ucomm.

 

SORT s_ucomm BY low ASCENDING.

 

IF fcode = 'ENT1'.

   sy-ucomm = 'ENT1'.

ENDIF.

 

IF sy-ucomm IN s_ucomm AND sy-tcode = 'VB21'.

   DATA: lv_ksdat            LIKE t681-ksdat,

 

         lv_flag             TYPE flag,

         lv_no_popup         TYPE flag,

         lv_new_flag         TYPE flag,

         lv_old_flag         TYPE flag,

         lv_new_rec          TYPE flag,

         lv_zvflg_save_deal  TYPE zvflg_save_deal,

 

         lv_title(30),

         lv_answer,

         lv_question(400),

 

         lv_matnr            TYPE matnr,

 

         lv_knuma_ag         TYPE knuma_ag,

 

         lv_new_datab        TYPE kodatab,     " nowa data poczatkowa obowiazywania warunku

         lv_new_datbi        TYPE kodatbi,     " nowa data koncowa obowiazywania warunku

 

         lv_old_datab        TYPE kodatab,     " aktualna data poczatkowa obowiazywania warunku

         lv_old_datbi        TYPE kodatbi.     " aktualna data koncowa obowiazywania warunku

 

   DATA : BEGIN OF s_komg .

           INCLUDE STRUCTURE komg.

   DATA : END OF  s_komg .

 

   IMPORT lv_popup TO lv_no_popup FROM MEMORY ID sy-uname.

 

   PERFORM time_vake_akt_fill(sapmv130) USING no.

*if not TIME_VAKE_AKT[] is INITIAL.

*    READ TABLE time_vake_akt INDEX 1

**  TCTRL_FAST_ENTRY-CURRENT_LINE

*    .

*

*    IF sy-subrc = 0.

   LOOP AT  time_vake_akt.

         PERFORM vake_next(sapmv130) USING yes.

 

         IF NOT rv13a-datab = '00000000'.

           lv_new_datab = rv13a-datab.

         ELSE.

           lv_new_datab = rv130-datab.

         ENDIF.

 

         IF NOT rv13a-datbi = '00000000'.

           lv_new_datbi = rv13a-datbi.

         ELSE.

           lv_new_datbi = rv130-datbi.

         ENDIF.

 

     READ TABLE S_KNUMH WITH KEY KNUMH = time_vake_akt-knumh

                                 DATAB = lv_new_datab

                                 DATBI = lv_new_datBI.

 

     IF NOT SY-SUBRC = 0.

       CALL FUNCTION 'SD_CONDITION_KOMG_FILL'

         EXPORTING

           p_kotabnr = time_vake_akt-kotabnr

           p_kvewe   = time_vake_akt-kvewe

           p_vakey   = time_vake_akt-vakey

         IMPORTING

           p_komg    = s_komg.

 

       SELECT SINGLE zvflg_save_deal FROM zpon INTO lv_zvflg_save_deal

         WHERE vkorg = kona-vkorg

           AND vtweg = kona-vtweg

           AND spart = kona-spart

           AND kunnr = s_komg-kunnr.

 

       IF NOT sy-subrc = 0.

         SELECT SINGLE zvflg_save_deal FROM zpon INTO lv_zvflg_save_deal

          WHERE vkorg = kona-vkorg

            AND vtweg = kona-vtweg

            AND spart = kona-spart.

 

         IF NOT sy-subrc = 0.

           EXIT.

         ENDIF.

       ENDIF.

 

       IF lv_zvflg_save_deal = 'X'.

         lv_old_datab = time_vake_akt-datab.

 

         lv_old_datbi = time_vake_akt-datbi.

 

         lv_matnr = s_komg-matnr.

 

         SELECT SINGLE knuma_ag FROM konp INTO lv_knuma_ag

           WHERE knumh = time_vake_akt-knumh.

*    ENDIF.

 

*if not lv_new_rec = 'X'.

         IF ( ( lv_new_datab = '00000000' ) AND ( lv_new_datbi = '00000000' ) ).

           lv_new_flag = ''.

         ENDIF.

 

         IF ( ( lv_old_datab = '00000000' ) AND ( lv_old_datbi = '00000000' ) ).

           lv_old_flag = ''.

         ENDIF.

 

         IF ( lv_new_datbi = lv_old_datbi ) AND ( lv_old_datab BETWEEN lv_new_datab AND lv_new_datbi ).

           lv_old_flag = 'X'.

         ENDIF.

 

         IF ( lv_new_datbi = lv_old_datab ) AND ( lv_new_datab < lv_old_datab ).

           lv_old_flag = 'X'.

         ENDIF.

 

         IF ( lv_new_datab = lv_old_datab ) AND ( lv_new_datbi BETWEEN lv_old_datab AND lv_old_datbi ).

           lv_new_flag = 'X'.

         ENDIF.

 

         IF ( lv_new_datbi > lv_old_datbi ) AND ( lv_new_datab BETWEEN lv_old_datab AND lv_old_datbi ).

           lv_new_flag = 'X'.

         ENDIF.

 

         IF ( lv_new_datab < lv_old_datab ) AND ( lv_new_datbi BETWEEN lv_old_datab AND lv_old_datbi ).

           lv_new_flag = 'X'.

         ENDIF.

 

         IF ( lv_new_datbi = lv_old_datbi ) AND ( lv_new_datab BETWEEN lv_old_datab AND lv_old_datbi ).

           lv_new_flag = 'X'.

         ENDIF.

 

         IF ( lv_new_datab = lv_old_datab ) AND ( lv_old_datbi BETWEEN lv_new_datab AND lv_new_datbi ).

           lv_new_flag = ''.

         ENDIF.

 

         IF ( lv_new_datbi = lv_old_datbi ) AND ( lv_new_datab BETWEEN lv_old_datab AND lv_old_datbi ).

           lv_old_flag = 'X'.

         ENDIF.

 

         IF ( lv_new_datab = lv_old_datbi ) AND ( lv_new_datbi > lv_old_datbi ).

           lv_new_flag = 'X'.

         ENDIF.

 

*    IF ( ( lv_new_datab BETWEEN lv_old_datab AND lv_old_datbi ) AND ( lv_new_datbi BETWEEN lv_old_datab AND lv_old_datbi ) ).

IF ( ( lv_new_datab > lv_old_datab AND lv_new_datab < lv_old_datbi ) AND ( lv_new_datbi < lv_old_datbi  AND lv_new_datbi > lv_old_datab ) ).

           lv_old_flag = ''.

           lv_new_flag = ''.

         ENDIF.

 

 

* IF ( ( lv_old_datab BETWEEN lv_new_datab AND lv_new_datbi ) AND ( lv_old_datbi BETWEEN lv_new_datab AND lv_new_datbi ) ).

if ( lv_old_datab > lv_new_datab ) and ( LV_OLD_DATBI < LV_new_DATBI ).

*           lv_old_flag = ''.

           lv_old_flag = 'X'.

*           lv_new_flag = ''.

         ENDIF.

 

         IF lv_new_flag = 'X' OR lv_old_flag = 'X'.

*      IF ( NOT lv_new_datab = lv_old_datab ) and ( NOT lv_new_datbi = lv_old_datbi ).

* if ( ( not lv_new_datab BETWEEN lv_old_datab and lv_old_datbi ) and ( not lv_new_datbi BETWEEN lv_old_datab and lv_old_datbi ) ).

           lv_flag = 'X'.

 

CONCATENATE 'The validity period of new condition overlaps with different conditions. These conditions will be edited when you save! Material:' lv_matnr

           ', Old Sales Deal:' lv_knuma_ag

           ', New beginnig date: ' lv_new_datab ', New end date: '

           lv_new_datbi '. Old beginning date: '

           lv_old_datab ', Old end date: ' lv_old_datbi '. Are You Sure?' INTO lv_question.

 

*    endif.

*      ENDIF.

         ENDIF.

 

*endif.

*endloop.

 

         IF lv_flag = 'X'.

           IMPORT lv_answer TO lv_answer FROM MEMORY ID 'ANSWER'.

 

           IF

*             lv_no_popup = '' OR

             ( ( lv_answer IS INITIAL ) OR ( lv_answer = 'A' ) ).

             CALL FUNCTION 'POPUP_TO_CONFIRM'

               EXPORTING

                titlebar                    = 'Sales Deal Warning'

*     DIAGNOSE_OBJECT             = ' '

                 text_question               = lv_question

                text_button_1               = 'Yes'

                icon_button_1               = ' '

                text_button_2               = 'No'

                icon_button_2               = ' '

                default_button              = '2'

                display_cancel_button       = 'X'

*     USERDEFINED_F1_HELP         = ' '

                start_column                = 25

                start_row                   = 6

*     POPUP_TYPE                  =

*     IV_QUICKINFO_BUTTON_1       = ' '

*     IV_QUICKINFO_BUTTON_2       = ' '

              IMPORTING

                answer                      = lv_answer

*     TABLES

*     PARAMETER                   =

              EXCEPTIONS

                text_not_found              = 1

                OTHERS                      = 2.

 

             EXPORT lv_answer TO MEMORY ID 'ANSWER'.

 

             IF lv_answer = '1' OR lv_answer = '2'.

               lv_no_popup = 'X'.

 

               EXPORT lv_no_popup TO MEMORY ID 'NO_POPUP'.

 

               lv_ksdat = t681-ksdat.

 

               CLEAR t681-ksdat.

 

               IF lv_answer = '2'.

                 s_knumh-DATBI = lv_new_datbi.

                 s_knumh-DATAB = lv_new_datAB.

                 s_knumh-KNUMH = time_vake_akt-knumh.

                 APPEND s_knumh.

 

               ENDIF.

             ENDIF.

           ELSE.

 

             IF lv_answer = '1'

*               OR lv_answer = '2'

               .

               lv_no_popup = 'X'.

 

               EXPORT lv_no_popup TO MEMORY ID 'NO_POPUP'.

 

               lv_ksdat = t681-ksdat.

 

               CLEAR t681-ksdat.

 

*               IF lv_answer = '2'.

*

*                 s_knumh-DATBI = lv_new_datbi.

*                 s_knumh-DATAB = lv_new_datAB.

*                 s_knumh-KNUMH = time_vake_akt-knumh.

*                 APPEND s_knumh.

*

*               ENDIF.

 

             ENDIF.

           ENDIF.

         ENDIF.

       ENDIF.

       CLEAR: lv_new_datab, lv_old_datab, lv_new_datbi, lv_old_datbi, lv_knuma_ag, lv_new_flag, lv_old_flag.

     ENDIF.

   ENDLOOP.

 

   DELETE ADJACENT DUPLICATES FROM s_knumh.

 

   EXPORT s_knumh TO MEMORY ID 'KNUMH'.

 

ENDIF.

  1. ENDENHANCEMENT.

*$*$-End:   (1)---------------------------------------------------------------------------------$*$*

  LOCAL: ivake,

         konp, xkonp,

         vake, xvake, time_vake, time_vake_key,

         read_tabix, rv13a,

         konh,

         svake,

         skonp,

         ivake_tabix_selkz,

         low_tabix_ivake,

         high_tabix_ivake.

  DATA: ivake_tabix LIKE sy-tabix,

        overlap,

        save_dyngr LIKE sy-dyngr,

        column_left TYPE p.

  DATA: BEGIN OF save_xvake_tab OCCURS 0.

          INCLUDE STRUCTURE xvake.

  DATA: END OF save_xvake_tab.

  DATA: BEGIN OF save_ivake_tab OCCURS 0.

          INCLUDE STRUCTURE ivake.

  DATA: END OF save_ivake_tab.

  DATA: BEGIN OF save_xkonp_tab OCCURS 0.

          INCLUDE STRUCTURE xkonp.

  DATA: END OF save_xkonp_tab.

  save_dyngr = sy-dyngr.

  save_xkonp_tab[] = xkonp[].

  save_xvake_tab[] = xvake[].

  ivake_check = all.

  REFRESH save_ivake_tab.

 

  gp_subrc = 0.

  CHECK fcode = fcode_sichern      OR

        fcode = fcode_v13a_sichern OR

        fcode = fcode_weiter.

* Structure with Validity Periods ?

  IF t681-ksdat = charx.

* Initialize mimimum and maximum ivake indices

    CLEAR: low_tabix_ivake, high_tabix_ivake, ivake_tabix_selkz.

* Build ivake if needed

    save_ivake_tab[] = ivake[].

    IF ivake_check = 'X' AND sy-dyngr NE 'VARS'.

      REFRESH ivake.

      LOOP AT xvake.

        MOVE-CORRESPONDING xvake TO ivake.

        ivake-tabix = sy-tabix.

        APPEND ivake.

      ENDLOOP.

      SORT ivake.

    ENDIF.

* Read all Conditions from ivake

    LOOP AT ivake.

* For variable screen, don't process dummy entries in ivake

      CHECK NOT ivake-kotabnr IS INITIAL.

* Process only 1 KNUMH or all KNUMH's ???

      IF ivake_check = ' '.

        CHECK ivake-knumh = vake-knumh.

      ENDIF.

* Mark Position in table IVAKE

      ivake_tabix = sy-tabix.

* Initialize overlap flag

      CLEAR overlap.

* Read XVAKE

      READ TABLE xvake INDEX ivake-tabix.

* Check to make sure it's an agreement

      IF abtyp_general NE abtyp-agreement.

        IF ivake_check = ' '.

          CHECK NOT konp-knuma_ag IS INITIAL.

        ELSE.

          READ TABLE xkonp INDEX xvake-tabix2.

          CHECK NOT xkonp-knuma_ag IS INITIAL.

        ENDIF.

      ENDIF.

* If dates have changed then update XVAKE with new ones (reset later)

      IF ivake_check = ' '.

        IF xvake-datab NE rv13a-datab.

          xvake-datab = rv13a-datab.

          MODIFY xvake INDEX ivake-tabix.

        ENDIF.

        IF xvake-datbi NE rv13a-datbi.

          xvake-datbi = rv13a-datbi.

          MODIFY xvake INDEX ivake-tabix.

        ENDIF.

      ENDIF.

* Change made ?

      IF xvake-updkz <> space.

        MOVE-CORRESPONDING xvake TO time_vake_key.

* Read time-dependent records

        READ TABLE time_vake WITH KEY time_vake_key BINARY SEARCH.

* Fill the table with the actual validity periods

        WHILE sy-subrc    = 0               AND

              xvake-kotabnr = time_vake-kotabnr AND

              xvake-kschl = time_vake-kschl AND

              xvake-vakey = time_vake-vakey.

* Next record in table

          read_tabix = sy-tabix + 1.

* Check to see if another condition record that is active and assigned

* to a sales deal overlaps with the record being processed.

          IF NOT ( xvake-updkz = updkz_update    AND        "Update

                   xvake-knumh = time_vake-knumh ).         "Same record

            SELECT * FROM konp

                   WHERE knumh = time_vake-knumh.

              EXIT.

            ENDSELECT.

            IF NOT konp-knuma_ag IS INITIAL AND             "agreement

               konp-loevm_ko IS INITIAL.                    "not deleted

              IF ( time_vake-datab <  xvake-datab AND     "limited

                   time_vake-datbi <= xvake-datbi AND

                   time_vake-datbi >= xvake-datab ) OR

                 ( time_vake-datab >= xvake-datab AND    "limited

                   time_vake-datab <= xvake-datbi AND

*                ( time_vake-datab >= xvake-datab and    "total overlap

*                  time_vake-datbi <= xvake-datbi ) or

                   time_vake-datbi >  xvake-datbi ) OR

                 ( time_vake-datab < xvake-datab AND     "split

                   time_vake-datbi > xvake-datbi ).

* Set Overlap Flag

                overlap = charx.

                gp_subrc = 4.

                EXIT.

              ENDIF.

            ENDIF.

          ENDIF.

* Read next record

          READ TABLE time_vake INDEX read_tabix.

        ENDWHILE.

      ENDIF.

* Set Selection Flag

      ivake-selkz = overlap.

      MODIFY ivake.

* Set smallest and largest indices for range of overlapping records

      IF overlap = charx.

        IF low_tabix_ivake IS INITIAL.

          low_tabix_ivake   = ivake_tabix.

          gp_subrc = 8.

        ENDIF.

        high_tabix_ivake = ivake_tabix.

      ENDIF.

    ENDLOOP.

  ENDIF.

  IF gp_subrc NE 0.

    IF NOT low_tabix_ivake IS INITIAL.

      time_vakey = space.

      PERFORM vake_next(sapmv130) USING yes.

* Call error popup window

      CALL SCREEN 123 STARTING AT 20 1.

      CLEAR time_vakey.

* Delete/mark entries

      LOOP AT ivake.

        IF ivake-selkz = updkz_delete.

          DELETE ivake.

        ENDIF.

        IF ivake-selkz = char_plus OR

           ivake-selkz = charx.

          ivake-selkz = charx.

          MODIFY ivake.

        ENDIF.

      ENDLOOP.

    ENDIF.

  ENDIF.

* Set XVAKE back to how it was upon entering this form

* (in some cases, we modified the DATAB and DATBI dates)

  REFRESH xvake.

  xvake[] = save_xvake_tab[].

  xkonp[] = save_xkonp_tab[].

* Loop at saved ivake and update the selection indicator

* for entries with errors

  DESCRIBE TABLE save_ivake_tab LINES sy-tfill.

  IF sy-tfill <> 0.

    IF ( sichern = 'X' ) AND

       ( save_dyngr = 'SEER' OR save_dyngr = 'VARS' ).

      LOOP AT save_ivake_tab.

        MOVE-CORRESPONDING save_ivake_tab TO time_vake_key.

        READ TABLE ivake WITH KEY time_vake_key BINARY SEARCH.

        IF sy-subrc = 0.

          IF ivake-selkz NE save_ivake_tab-selkz.

            MOVE ivake-selkz TO save_ivake_tab-selkz.

            MODIFY save_ivake_tab.

          ENDIF.

        ENDIF.

      ENDLOOP.

    ENDIF.

    ivake[] = save_ivake_tab[].

  ENDIF.

  ivake_tabix_selkz = 0.

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""$"$\SE:(2) Form GUELTIGKEIT_PRUEFEN_VERKAUFSAK, End A

*$*$-Start: (2)---------------------------------------------------------------------------------$*$*

ENHANCEMENT 2  Z_MV13AFOG.    "active version

if

*   lv_flag = 'X' and

   lv_answer = '1' or lv_answer = '2'.

t681-ksdat = lv_ksdat.

ENDIF.

  1. ENDENHANCEMENT.

*$*$-End:   (2)---------------------------------------------------------------------------------$*$*

  1. ENDFORM.                    "GUELTIGKEIT_PRUEFEN_VERKAUFSAK

 

 

  1. 2.  MV13AF0K

 

*---------------------------------------------------------------------*

*       FORM KONDITION_SICHERN                                        *

*---------------------------------------------------------------------*

*       Aufruf des Programms zur Fortschreibung der Konditionssätze   *

*---------------------------------------------------------------------*

FORM kondition_sichern.

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""$"$\SE:(1) Form KONDITION_SICHERN, Start A

*$*$-Start: (1)---------------------------------------------------------------------------------$*$*

ENHANCEMENT 3  Z_MV13AFOG.    "active version

* wylaczenie pop-upa przy drugim przebiegu

  data: lv_popup type flag VALUE 'X'.

 

  IMPORT lv_no_popup TO lv_popup FROM MEMORY ID 'NO_POPUP'.

 

  EXPORT lv_popup to MEMORY ID sy-uname.

  1. ENDENHANCEMENT.

*$*$-End:   (1)---------------------------------------------------------------------------------$*$*

 

  DATA: bomat_okay        TYPE c,

        einheiten_okay    TYPE c,

        partner_okay      TYPE c,

        waers_okay        TYPE c,

        save_xvake        LIKE xvake,

        l_answer          TYPE c,

        lt_error_messages LIKE arrangerra

                          OCCURS 0 WITH HEADER LINE.

 

* ZUrücksetzen Returncode

  read_subrc = 0.

 

* Datumüberlappungsprüfung

  IF t681-ksdat = charx AND

* im Batch-Input nicht erforderlich

     syst-binpt = space AND

* keine Prüfung bei Bonus-Konditionen

     abtyp_general NA abtyp-bonus_all.

* check if agreement number exists for any xvake

    save_xvake = xvake.

    IF abtyp_general NE abtyp-agreement.

      LOOP AT xvake.

*        skonp-tabix = xvake-tabix2.            "note 1358096

        READ TABLE xkonp INDEX xvake-tabix2.

        IF NOT xkonp-knuma_ag IS INITIAL.

          EXIT.

        ENDIF.

      ENDLOOP.

    ENDIF.

* if agreement number exists for any xvake or in sales deal, check

* for overlaps

    IF abtyp_general = abtyp-agreement OR

       NOT xkonp-knuma_ag IS INITIAL.

* Gueltigkeit pruefen für alle Konditionen in Absprache

      PERFORM gueltigkeit_pruefen_verkaufsak

                               USING 'X' 'X'

                               CHANGING  read_subrc.

      IF ivake-knumh NE vake-knumh.

        MOVE-CORRESPONDING vake TO time_vake_key.

        READ TABLE ivake WITH KEY time_vake_key BINARY SEARCH.

      ENDIF.

      IF read_subrc NE 0.

        svake-tabix = ivake-tabix.

        fcode = fcode_gleiche_seite.

        PERFORM fcode_bearbeiten(sapmv130)

                  USING fcode agidv t681s-dynpronr t685-posgr.

        EXIT.

      ENDIF.

    ENDIF.

    xvake = save_xvake.

* Gueltigkeit pruefen bzgl. Budgetierung

    PERFORM budget_date_check

               USING rv13a-datab rv13a-datbi yes

               CHANGING  read_subrc.

    IF read_subrc = 8.

      fcode = fcode_gleiche_seite.

      PERFORM fcode_bearbeiten(sapmv130)

              USING fcode agidv t681s-dynpronr t685-posgr.

      EXIT.

    ENDIF.

* Gueltigkeit pruefen bzgl. Überlappung

    PERFORM gueltigkeitspruefung USING read_subrc.

  ENDIF.

* Nachbearbeitung erforderlich ?

  IF read_subrc = 8.

* auf das Schnellerfassungsbilc

    fcode = fcode_gleiche_seite.

    PERFORM fcode_bearbeiten(sapmv130)

            USING fcode agidv t681s-dynpronr t685-posgr.

  ELSE.

    IF abtyp_general CA abtyp-bonus_all.

      PERFORM bomat_vollstaendig USING bomat_okay.

      IF bomat_okay = no.

        IF used_by_idoc = no.          "WD_IDOC

          MESSAGE i199.

          fcode = fcode_bomat.

        ELSE.                          "WD_IDOC

          returncode = 20.             "WD_IDOC

          fcode = fcode_leave_dialog.  "WD_IDOC

        ENDIF.                         "WD_IDOC

* und wieder einmal in Fcode-Bearbeitung

        PERFORM fcode_bearbeiten(sapmv130)

                USING fcode agidv t681s-dynpronr t685-posgr.

        EXIT.

      ENDIF.

      PERFORM kondper_kmein_vollstaendig USING einheiten_okay.

      IF einheiten_okay = no.

* Kondition lesen

        READ TABLE xkonp INDEX xvake-tabix2.

        konp = xkonp.

         *konp = konp.

        skonp-tabix = xvake-tabix2.

        IF used_by_idoc = no.          "WD_IDOC

          MESSAGE i013(mn).

          fcode = fcode_var_sicht.

        ELSE.                          "WD_IDOC

          returncode = 21.             "WD_IDOC

          fcode = fcode_leave_dialog.  "WD_IDOC

        ENDIF.                         "WD_IDOC

* und wieder einmal in Fcode-Bearbeitung

        PERFORM fcode_bearbeiten(sapmv130)

                USING fcode agidv t681s-dynpronr t685-posgr.

        EXIT.

      ENDIF.

* Staffeln Komplett gepflegt (Auf Bezugsgröße prüfen)

      PERFORM staffel_complet_check USING staffel_einheiten_okay.

      IF staffel_einheiten_okay NE yes.

* Kondition lesen

        READ TABLE xkonp INDEX xvake-tabix2.

        konp = xkonp.

         *konp = konp.

        skonp-tabix = xvake-tabix2.

        IF used_by_idoc = no.          "WD_IDOC

          IF staffel_einheiten_okay = no.

            MESSAGE i010(mn).

          ENDIF.

          fcode = fcode_var_sicht.

        ELSE.                          "WD_IDOC

          returncode = 22.             "WD_IDOC

          fcode = fcode_leave_dialog.  "WD_IDOC

        ENDIF.                         "WD_IDOC

* und wieder einmal in Fcode-Bearbeitung

        PERFORM fcode_bearbeiten(sapmv130)

                USING fcode agidv t681s-dynpronr t685-posgr.

        EXIT.

      ENDIF.

* Absprachepartner gepflegt prüfen

* keine Prüfung bei Idoc Verarbeitung

      IF used_by_idoc = no.            "WD_IDOC

        PERFORM absprachepartner_complete USING partner_okay.

        IF partner_okay = no.

          fcode = fcode_bonus_partner.

* und wieder einmal in Fcode-Bearbeitung

          PERFORM fcode_bearbeiten(sapmv130)

                 USING fcode agidv t681s-dynpronr t685-posgr.

          EXIT.

        ENDIF.

      ENDIF.                           "WD-IDOC

* Absprachewaehrungen prüfen

* keine Prüfung bei Idoc Verarbeitung

      IF used_by_idoc = no.            "WD_IDOC

        PERFORM absprache_waehrung_check USING waers_okay.

        IF waers_okay = no.

          fcode = fcode_gleiche_seite.

* und wieder einmal in Fcode-Bearbeitung

          PERFORM fcode_bearbeiten(sapmv130)

                 USING fcode agidv t681s-dynpronr t685-posgr.

          EXIT.

        ENDIF.

      ENDIF.                           "WD-IDOC

      IF used_by_idoc = no.            "WD_IDOC

* Falls Bonus Einkauf und nicht anzeige

        IF abtyp_general = abtyp-bonus_ein

                         AND t180-aktyp <> aktyp-display.

* Meldungen

* Nachrichtenfindung nötig

          CALL FUNCTION 'MM_ARR_START_NAFI_BY_ANBED'

            EXPORTING

              i_kappl           = t6b1-kappl_kona

              i_kalsm           = t6b1-kalsm_kona

              i_kona            = kona

            IMPORTING

              e_answer          = l_answer

            TABLES

              t_mmpa            = xmmpa

              t_error_messages  = lt_error_messages

            EXCEPTIONS

              inconsistent_data = 1

              OTHERS            = 2.

* Normales Fehler

          IF sy-subrc <> 0.

* Meldung ausgeben

            MESSAGE ID sy-msgid TYPE 'W' NUMBER sy-msgno

                    WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.

          ENDIF.

* Fehlerfall

          IF NOT lt_error_messages[] IS INITIAL.

* Meldung absetzen via FB

            CALL FUNCTION 'MM_ARRANG_DISP_ARRANG_ERR_MSG'

              TABLES

                error_messages = lt_error_messages[].

          ENDIF.

* Abbrechen aktiv

          IF l_answer = 'A'.

            fcode = fcode_gleiche_seite.

* und wieder einmal in Fcode-Bearbeitung

            PERFORM fcode_bearbeiten(sapmv130)

                   USING fcode agidv t681s-dynpronr t685-posgr.

            EXIT.

          ENDIF.

        ENDIF.

      ENDIF.                           "WD-IDOC

    ENDIF.

 

* Check consistency of scale group

    IF abtyp_general = abtyp-bonus.

      DATA: BEGIN OF check_scale OCCURS 0,

              prsch LIKE konp-prsch,

              kzbzg LIKE konp-kzbzg,

              konms LIKE konp-konms,

              konws LIKE konp-konws,

            END OF check_scale.

      CLEAR read_subrc.

      LOOP AT xkonp WHERE NOT prsch IS INITIAL.

        READ TABLE check_scale WITH KEY prsch = xkonp-prsch.

        IF check_scale-prsch EQ xkonp-prsch AND

         ( check_scale-kzbzg NE xkonp-kzbzg  OR

           check_scale-konms NE xkonp-konms  OR

           check_scale-konws NE xkonp-konws ).

          read_subrc = 4.

          EXIT.

        ELSE.

          MOVE-CORRESPONDING xkonp TO check_scale.

          COLLECT check_scale.

        ENDIF.

      ENDLOOP.

      IF NOT read_subrc IS INITIAL.

        MESSAGE i493 WITH check_scale-prsch.

        fcode = fcode_gleiche_seite.

        PERFORM fcode_bearbeiten(sapmv130)

                USING fcode agidv t681s-dynpronr t685-posgr.

        EXIT.

      ENDIF.

    ENDIF.

* Datenbankänderung durchführen

    PERFORM kondition_sichern_db.

* kein Entsperren der Sätze

    dequeue_all = no.

    IF control_flags-no_navigation EQ abap_true.

      EXIT.

    ENDIF.

* Zum Anforderungsbild zurueck

    PERFORM anforderungsbild.

  ENDIF.

  1. ENDFORM.                    "kondition_sichern

Changing Subject of Mail sent through "Spool Recipient"

$
0
0

Scenario: We usually use the “Spool Recipient” of the SM37 Background Job  to send the Spool Outputs to designated users
in their Work Place Inbox.

 

Spool Recipient:

1.jpg


Workplace Inbox:

2.jpg

 

If you notice the Subject of the Item, it takes theBackground Jobs Name & Step Number & we obviously Didn’t Like that

 

3.jpg

 

What we did:

 

After some research, we stumbled upon one SAP Note which will allow us this to change.

 

Note number: 1101211 - Using spool request title as e-mail  title.

 

This Note allows you to set the Title of your Email to be  the Title of your Spool Request.

 

So, We thought if we could have our Spool contain the Namewhich we wanted, it would definitely flow to the Title of the Email sent to Workplace Inbox,

We went about this in 2 Steps

 

  1. Do what the SAP Note said

 

Run the Program RSPO0021 with the Below Parameters:

 

4.jpg

 

Once this is done, we proceed with a way to change the Spool Request Name.

 

 

2.   Since ours was a Custom Program calling a Standard Program, we passed the Name we wanted to the Spool Parameters Id along with the Calling
Program.

 

In the Below screenshot we call the Standard Program “RFEBCK00”,so in the Spool  Parameters we passed the needed values.

 

5.jpg


6.jpg

 

So, if your case is a Standard Program just change it in the Spool Title” while setting the Print Parameters.

 

 

 

After these changes we ran the Custom Program and went to check the Output and see if the Name on the work item is changed


We checked first if the Spool got the Name we wanted,

7.jpg

The above screen says we did!

 

Next, we want to check the all Important One

 

8.jpg

 

Thankfully the effort paid off !

How to Call DLL Functions Inside ABAP

$
0
0

Hello community,

 

a long time ago I presented here a possibility how to call DLL functions from a library of the presentation server inside ABAP.

 

Not so long ago I presented here the possibility how to use Windows PowerShell inside ABAP.

 

Here now a symbiosis, how to call DLL functions via PowerShell inside ABAP:


"-Begin-----------------------------------------------------------------

  Program zCallDLL.

 

    "-TypePools---------------------------------------------------------
      Type-Pools OLE2 .

 

    "-Constants---------------------------------------------------------
      Constants CrLf(2) Type c Value %_CR_LF.
      Constants OUTPUT_CONSOLE Type i Value 0.
      Constants OUTPUT_WINDOW Type i Value 1.
      Constants OUTPUT_BUFFER Type i Value 2.

 

    "-Variables---------------------------------------------------------
      Data PS Type OLE2_OBJECT.
      Data Result Type i Value 0.
      Data strResult Type String Value ''.
      Data tabResult Type Table Of String.
      Data PSCode Type String Value ''.

 

    "-Macros------------------------------------------------------------
      Define _.
        Concatenate PSCode &1 CrLf Into PSCode.
      End-Of-Definition.

 

    "-Main--------------------------------------------------------------
      Create Object PS 'SAPIEN.ActiveXPoSH'.

      If sy-subrc = 0 And PS-Handle <> 0 And PS-Type = 'OLE2'.

 

        Call Method Of PS 'Init' = Result Exporting #1 = 0.

        If Result = 0.

 

          Call Method Of PS 'IsPowerShellInstalled' = Result.

          If Result <> 0.

            Set Property Of PS 'OutputMode' = OUTPUT_BUFFER.

 

_ '$sig = @"'.
_ '[DllImport("User32.dll")]'.
_ 'public static extern int MessageBoxA(int hWnd, String Text, String Caption, int Type);'.
_ '"@;'.
_ '$DLL_User32 = Add-Type PBexpMsgBox -MemberDefinition $sig -PassThru'.
_ '$DLL_User32::MessageBoxA(0, "Hello World", "From WinAPI", 0);'.

 

            Call Method Of PS 'Execute' Exporting
              #1 = PSCode.

 

            Call Method Of PS 'OutputString' = strResult.

 

            Split strResult At cl_abap_char_utilities=>cr_lf
              Into Table tabResult.

            Loop At tabResult Into strResult.
              Write: / strResult.
            EndLoop.

 

          EndIf.

 

        EndIf.

 

        Free Object PS.

 

      EndIf.

"-End-------------------------------------------------------------------

 

The example above shows the using of a WinAPI call.

 

Good DLL calling.

 

Cheers

Stefan


Viewing all 935 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>