Tuesday, July 19, 2011

Spreading single line item with quantity > 1 to multiple line items with quantity = 1 in Sales Document

Once I was asked to make an enhancement on contract creation process. The requirement is that when someone wants to create a contract based on a quotation, a line item read in the quotation with quantity more than one should be spread to multiple line items with quantity of one.

Examples:
  • If the quotation contains 1 line items with quantity = 3, then the contract should be 3 line items with quantity = 1 (of the same material.)
  • If the quotation contains 2 line items with quantity = 3 and 2, then the contract should be 5 line items with quantity = 1 (first material for the first 3 line items, and the second material for the last 2.)
Simple right? The solution is realy as simple as the requirement. But to get to the solution I have to face a very hard time. I have to figure out what exit(s) I should use and what to do in it.

For once, I can get the items spread as the requirement ask but when I see the billing plan and pricing condition of the items, I recognise that they are not spread at all. I stuck at this condition for some days, trying to figure out how to properly recalculate the billing plan and the pricing condition.

Finally I ask a friend for a help. He help me trace the code and then he tries something that I would never think of. That is when spreading the line items he did not resequence the item numbers. He let it duplicated so the links to other data in memory are still intact. That's the solution.

From there I am doing more tests and figure out that I can strip out much of my previous codes because most of other data will be regenerated from the copied vbap only.

After much trial, I finally choose the user exit USEREXIT_MOVE_FIELD_TO_VBAK in program SAPMV45A to put my code, because it is where I can get a complete copy of VBAP in CVBAP internal table and not much processing has been done.

So here is the code:

FORM userexit_move_field_to_vbak.
DATA: lt_cvbap LIKE TABLE OF cvbap WITH HEADER LINE,
ld_quantity TYPE i.

CASE fcode.
WHEN 'RKON'.
IF ( sy-tcode = 'VA41' ). "contract creation
LOOP AT cvbap INTO lt_cvbap.
ld_quantity = lt_cvbap-zmeng / 1000.
DIVIDE:
lt_cvbap-zmeng BY ld_quantity,
lt_cvbap-orfmng BY ld_quantity,
lt_cvbap-netwr BY ld_quantity,
lt_cvbap-netpr BY ld_quantity.

DO ld_quantity TIMES.
APPEND lt_cvbap.
ENDDO.
ENDLOOP.

cvbap[] = lt_cvbap[].
ENDIF.
ENDCASE.

ENDFORM.

Wednesday, October 21, 2009

Updating long text in IW32 and IW62

If you change the long texts in IW32 and IW62 using the function module SAVE_TEXT, you will not be able to see the text from the TCodes, even though you can see the text when you use function module READ_TEXT. The problem is because both TCodes relies on values on other tables to determine the language used for the text.

Here is how to update the text for IW32:


form f_update_text
using fu_aufnr fu_vornr fu_ltxa1 fu_avot.

data:
ld_aufpl like afvc-aufpl,
ld_aplzl like afvc-aplzl,
ld_vornr(4) type n,
ld_name like stxh-tdname,
ld_subrc like sy-subrc.

ld_vornr = fu_vornr.
select single aufpl into ld_aufpl from caufv
where aufnr = fu_aufnr.

select single aplzl into ld_aplzl from afvc
where aufpl = ld_aufpl and vornr = ld_vornr.

concatenate sy-mandt ld_aufpl ld_aplzl into ld_name.

perform f_write_text
using ld_name fu_ltxa1 fu_avot
changing ld_subrc.

if ld_subrc is initial.
update afvc set txtsp = sy-langu
where aufpl = ld_aufpl and aplzl = ld_aplzl.
endif.

endform. "f_update_text


form f_write_text
using fu_name fu_shorttext fu_text
changing fc_subrc.

data:
lw_thead type thead,
lt_tline type table of tline with header line.

lw_thead-tdobject = 'AUFK'. "SO Header (table TTXOB)
lw_thead-tdspras = sy-langu.
lw_thead-tdname = fu_name.
lw_thead-tdid = 'AVOT'. "Header note 1 (table TTXID)

lt_tline-tdformat = '*'.
lt_tline-tdline = fu_shorttext.
append lt_tline.
lt_tline-tdformat = '*'.
lt_tline-tdline = fu_text.
append lt_tline.

call function 'SAVE_TEXT'
exporting
header = lw_thead
savemode_direct = 'X'
tables
lines = lt_tline
exceptions
id = 1
language = 2
name = 3
object = 4
others = 5.

if sy-subrc <> 0.
fc_subrc = sy-subrc.
message id sy-msgid type sy-msgty number sy-msgno
with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.

else.
clear fc_subrc.
endif.
endform. "f_write_text



And here is the code for IW62:


form f_update_text
using fu_aufnr fu_vornr fu_ltxa1 fu_avot.

data:
ld_aufpl like afvc-aufpl,
ld_aplzl like afvc-aplzl,
ld_vornr(4) type n,
ld_name like stxh-tdname,
ld_subrc like sy-subrc.

ld_vornr = fu_vornr.
select single aufpl aplzl into (ld_aufpl, ld_aplzl) from hivg
where aufnr = fu_aufnr and vornr = ld_vornr.


concatenate sy-mandt ld_aufpl ld_aplzl into ld_name.

perform f_write_text
using ld_name fu_ltxa1 fu_avot
changing ld_subrc.

if ld_subrc is initial.
update hivg set txtsp = sy-langu
where aufpl = ld_aufpl and aplzl = ld_aplzl.
endif.

endform. "f_update_text


form f_write_text
using fu_name fu_shorttext fu_text
changing fc_subrc.

data:
lw_thead type thead,
lt_tline type table of tline with header line.

lw_thead-tdobject = 'AUFK'. "SO Header (table TTXOB)
lw_thead-tdspras = sy-langu.
lw_thead-tdname = fu_name.
lw_thead-tdid = 'AVOT'. "Header note 1 (table TTXID)

lt_tline-tdformat = '*'.
lt_tline-tdline = fu_shorttext.
append lt_tline.
lt_tline-tdformat = '*'.
lt_tline-tdline = fu_text.
append lt_tline.

call function 'SAVE_TEXT'
exporting
header = lw_thead
savemode_direct = 'X'
tables
lines = lt_tline
exceptions
id = 1
language = 2
name = 3
object = 4
others = 5.

if sy-subrc <> 0.
fc_subrc = sy-subrc.
message id sy-msgid type sy-msgty number sy-msgno
with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.

else.
clear fc_subrc.
endif.
endform. "f_write_text