CLIENT | MANDT(Key) |
SALESORDER | VBELN(Key) |
BUSINESSPARTNER | SNWD_PARTNER_ID |
OVERALLSTATUS | SNWD_SO_OA_STATUS_CODE |
CHANGEDAT | TIMESTAMPL |
CREATEDAT | TIMESTAMPL |
CHANGEDBY | UNAME |
CREATEDBY | UNAME |
CLIENT | MANDT (Key) |
SALESORDER | VBELN (Key) |
SALESORDERITEM | SNWD_SO_ITEM_POS (Key) |
PRODUCT | SNWD_PRODUCT_ID |
GROSSAMOUNT | SNWD_TTL_GROSS_AMOUNT |
CURRENCYCODE | SNWD_CURR_CODE |
QUANTITY | INT4 |
@AbapCatalog.sqlViewName: 'ZVSOH'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Orders Headers'
@VDM: {
viewType: #BASIC
}
define view ZSalesOrderHeaders
as select from zso_head
{
key zso_head.salesorder,
zso_head.businesspartner,
zso_head.overallstatus,
zso_head.changedat,
zso_head.createdat,
zso_head.changedby,
zso_head.createdby
}
@AbapCatalog.sqlViewName: 'ZVSOI'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Items'
@VDM: {
viewType: #BASIC
}
define view ZSalesOrderItems
as select from zso_items
{
key zso_items.salesorder,
key zso_items.salesorderitem,
zso_items.product,
zso_items.grossamount,
zso_items.currencycode,
zso_items.quantity
}
@AbapCatalog.sqlViewName: 'ZSOHTP'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Header BO Layer'
@VDM: {
viewType: #TRANSACTIONAL
}
//****---->>>> Add the below objectModel code after activation of both header and items
@ObjectModel: {
transactionalProcessingEnabled: true,
compositionRoot: true,
createEnabled: true,
updateEnabled: true,
deleteEnabled: true,
draftEnabled: true,
writeDraftPersistence: 'zsoh_d',
semanticKey: [ 'salesorder' ]
}
define view ZI_SalesOrdersHeadTP
as select from ZSalesOrderHeaders as Header
// Assocations
association [0..*] to ZI_SalesOrderItems as _items on _items.salesorder = $projection.salesorder
// Values Helps
association [0..1] to SEPM_I_BusinessPartner as _BusinessPartner on $projection.businesspartner = _BusinessPartner.BusinessPartner
association [0..1] to Sepm_I_SalesOrdOverallStatus as _Status on $projection.overallstatus = _Status.SalesOrderOverallStatus
{
@ObjectModel.readOnly: true
key Header.salesorder,
@ObjectModel.foreignKey.association: '_BusinessPartner'
Header.businesspartner,
@ObjectModel.foreignKey.association: '_Status'
Header.overallstatus,
@ObjectModel.readOnly: true
Header.changedat,
@ObjectModel.readOnly: true
Header.createdat,
@ObjectModel.readOnly: true
Header.changedby,
@ObjectModel.readOnly: true
Header.createdby,
@ObjectModel.association: {
type: [ #TO_COMPOSITION_CHILD ]
}
_items,
// Value help assocations
_Status,
_BusinessPartner
}
transactionalProcessingEnabled: true,
compositionRoot: true,
draftEnabled: true,
writeDraftPersistence: 'zsoh_d',
semanticKey: [ 'salesorder' ]
@ObjectModel.foreignKey.association: '_BusinessPartner'
Header.businesspartner,
@ObjectModel.readOnly: true
@ObjectModel.association: {
type: [ #TO_COMPOSITION_CHILD ]
}
_items
@AbapCatalog.sqlViewName: 'ZSOITP'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Items BO Layer'
@VDM: {
viewType: #TRANSACTIONAL
}
//****---->>>> Add the below objectModel code after activation of both header and items
@ObjectModel:{
createEnabled: true,
updateEnabled: true,
deleteEnabled: true,
writeDraftPersistence: 'zsoi_d',
semanticKey:['salesorder', 'salesorderitem']
}
define view ZI_SalesOrderItems
as select from ZSalesOrderItems as Items
association [1..1] to ZI_SalesOrdersHeadTP as _header on _header.salesorder = $projection.salesorder
// Value Help
association [0..1] to SEPM_I_Product_E as _product on $projection.product = _product.Product
association [0..1] to SEPM_I_Currency as _currency on $projection.currencycode = _currency.Currency
{
@ObjectModel.readOnly: true
key Items.salesorder,
@ObjectModel.readOnly: true
key Items.salesorderitem,
@ObjectModel.mandatory: true
@ObjectModel.foreignKey.association: '_product'
Items.product,
@Semantics.amount.currencyCode: 'currencycode'
Items.grossamount,
@ObjectModel.foreignKey.association: '_currency'
@Semantics.currencyCode: true
Items.currencycode,
Items.quantity,
@ObjectModel.association: {
type: [ #TO_COMPOSITION_PARENT, #TO_COMPOSITION_ROOT ]
}
_header,
_product,
_currency
}
DATA:
ls_msg TYPE symsg.
" Get the message container, to push any messages to the UI if requred
IF eo_message IS NOT BOUND.
eo_message = /bobf/cl_frw_message_factory=>create_container( ).
ENDIF.
" header and items data declaration
DATA(lt_header) = VALUE ztisalesordersheadtp( ).
DATA(lt_items) = VALUE ztisalesorderitems( ).
"Read Header Data
"Pass the node key, which tells if we are trying to read header or item, in this case header
"Pass the draft keys, if we create an entry in the Fiori, they will be saved as draft intitial, those keys we will pass to get the data
io_read->retrieve(
EXPORTING
iv_node = zif_i_salesordersheadtp_c=>sc_node-zi_salesordersheadtp
it_key = it_draft_key
iv_fill_data = abap_true
IMPORTING
et_data = lt_header
).
" Read the Items data
" We need to read via the assocation, so passing the assocation key here
io_read->retrieve_by_association(
EXPORTING
iv_node = zif_i_salesordersheadtp_c=>sc_node-zi_salesordersheadtp " Node Name
it_key = it_draft_key " Key Table
iv_association = zif_i_salesordersheadtp_c=>sc_association-zi_salesordersheadtp-_items
iv_fill_data = abap_true
IMPORTING
et_data = lt_items " Data Return Structure
).
" Always 1 header only expected as we can only create one sales order at a time
DATA(ls_so_header) = CORRESPONDING zso_head( lt_header[ 1 ] ).
" Updating the header
GET TIME STAMP FIELD ls_so_header-changedat.
ls_so_header-changedby = sy-uname.
" I am checking if the sales order number is initial, it means it is the new entry
" Else it is an existing entry
" Alternatively we can also use lt_header[ 1 ]-HASACTIVEENTRY, which will tell if the active entry is available
" If the active entry is available means it is update sceanrio else it is create scenario
IF ls_so_header-salesorder IS NOT INITIAL.
MODIFY zso_head FROM ls_so_header.
ELSE.
GET TIME STAMP FIELD ls_so_header-createdat.
ls_so_header-createdby = sy-uname.
CALL FUNCTION 'NUMBER_GET_NEXT'
EXPORTING
nr_range_nr = '01'
object = 'ZSONR'
IMPORTING
number = ls_so_header-salesorder.
INSERT zso_head FROM ls_so_header.
ENDIF.
" Now update/create the items
DATA:
lt_items_save TYPE TABLE OF zso_items.
" Updating the items
SELECT COUNT( * )
FROM zso_items
INTO @DATA(lv_count)
WHERE salesorder = @ls_so_header-salesorder.
" Setting the item number here.
LOOP AT lt_items REFERENCE INTO DATA(lo_item) WHERE hasactiveentity EQ abap_false.
lv_count = lv_count + 1.
lo_item->salesorder = ls_so_header-salesorder.
lo_item->salesorderitem = lv_count.
CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
EXPORTING
input = lo_item->salesorderitem
IMPORTING
output = lo_item->salesorderitem. " Internal display of INPUT, any category
ENDLOOP.
lt_items_save = CORRESPONDING #( lt_items ).
IF lt_items_save IS NOT INITIAL.
MODIFY zso_items FROM TABLE lt_items_save.
ENDIF.
" Now we need to tell the BOPF framework to delete the draft entries as we have successfully created the data in the DB
" But BOPF only understands the data in in GUIDs, so we need to convert the sales order number to BOPF key, we just need to parent key
DATA(lr_key_util) = /bobf/cl_lib_legacy_key=>get_instance( zif_i_salesordersheadtp_c=>sc_bo_key ).
DATA(lv_bobf_key) = lr_key_util->convert_legacy_to_bopf_key(
iv_node_key = zif_i_salesordersheadtp_c=>sc_node-zi_salesordersheadtp
is_legacy_key = ls_so_header-salesorder ).
APPEND VALUE #( draft = it_draft_key[ 1 ]-key active = lv_bobf_key ) TO et_key_link.
" This is used in the update scenario of the sales order(which has already been created) and when we are creating sales order items
DATA:
lt_header TYPE ztisalesordersheadtp,
lt_items TYPE ztisalesorderitems.
" read the sales order items
io_read->retrieve(
EXPORTING
iv_node = zif_i_salesordersheadtp_c=>sc_node-zi_salesorderitems " Node Name
it_key = it_key
IMPORTING
et_data = lt_items
).
" Obviously one item is only expected, check if the sales order number is initial for the draft entry
READ TABLE lt_items REFERENCE INTO DATA(lo_item) INDEX 1.
IF lo_item->salesorder IS INITIAL.
" If initial, then get the header draft entry, which will have the sales order number via the assocation from child to header
io_read->retrieve_by_association(
EXPORTING
iv_node = zif_i_salesordersheadtp_c=>sc_node-zi_salesorderitems " Node Name
it_key = it_key " Key Table
iv_association = zif_i_salesordersheadtp_c=>sc_association-zi_salesorderitems-to_root
iv_fill_data = abap_true
IMPORTING
et_data = lt_header
).
" Update the salesorder item with the so number
lo_item->salesorder = lt_header[ key = lo_item->parent_key ]-salesorder.
io_modify->update(
EXPORTING
iv_node = zif_i_salesordersheadtp_c=>sc_node-zi_salesorderitems " Node
iv_key = lo_item->key " Key
iv_root_key = lo_item->root_key " NodeID
is_data = lo_item
).
ENDIF.
" To get only the active data as this code wil trigger for draft deletion as well
" For draft deletion the framework wil take care, for active, we need to.
/bobf/cl_lib_draft=>/bobf/if_lib_union_utilities~separate_keys(
EXPORTING iv_bo_key = is_ctx-bo_key
iv_node_key = is_ctx-node_key
it_key = it_key
IMPORTING
et_active_key = DATA(lt_active_bopf_keys)
).
"we will get the data in BOPF keys format, we need to get the sales order number from that
CHECK lt_active_bopf_keys IS NOT INITIAL.
DATA(ls_header) = VALUE zsk_isalesordersheadtp_active( ).
" Convert the bopf key to active document key
/bobf/cl_lib_draft=>/bobf/if_lib_union_utilities~get_active_document_key(
EXPORTING iv_bo_key = is_ctx-bo_key
iv_node_key = is_ctx-node_key
iv_bopf_key = lt_active_bopf_keys[ 1 ]-key
IMPORTING es_active_document_key = ls_header ).
" Delete the data
DELETE FROM zso_head WHERE salesorder = ls_header-salesorder.
DELETE FROM zso_items WHERE salesorder = ls_header-salesorder.
@AbapCatalog.sqlViewName: 'ZCSOH'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Orders Headers Consumption View'
@VDM.viewType: #CONSUMPTION
@Metadata: {
allowExtensions: true
}
@ObjectModel.transactionalProcessingDelegated: true
@ObjectModel: {
compositionRoot: true,
createEnabled: true,
updateEnabled: true,
deleteEnabled: true,
draftEnabled: true
}
@ObjectModel.semanticKey: [ 'salesorder' ]
@OData: {
publish: true
}
define view ZC_SalesOrdersHead
as select from ZI_SalesOrdersHeadTP as SalesOrderHeader
association [0..*] to ZC_SalesOrderItems as _items on _items.salesorder = $projection.salesorder
{
@UI.selectionField: [{
position: 10
}]
@UI.lineItem.position: 10
@UI.identification: [{
position: 10
}]
key SalesOrderHeader.salesorder,
@UI.lineItem.position: 20
@UI.identification: [{
position: 20
}]
SalesOrderHeader.businesspartner,
@UI.lineItem.position: 30
@UI.identification: [{
position: 30
}]
SalesOrderHeader.overallstatus,
@UI.lineItem.position: 40
@UI.lineItem.label:'Created on'
@UI.identification: [{
position: 40,
label:'Created on'
}]
SalesOrderHeader.createdat,
@UI.lineItem.position: 50
@UI.lineItem.label:'Created by'
@UI.identification: [{
position: 50,
label:'Created by'
}]
SalesOrderHeader.createdby,
@UI.lineItem.position: 60
@UI.lineItem.label: 'Changed on'
@UI.identification: [{
position: 60,
label:'Changed on'
}]
SalesOrderHeader.changedat,
@UI.lineItem.position: 70
@UI.lineItem.label:'Changed by'
@UI.identification: [{
position: 70,
label:'Changed by'
}]
SalesOrderHeader.changedby,
@ObjectModel.association: {
type: [ #TO_COMPOSITION_CHILD ]
}
_items,
// Associations
SalesOrderHeader._BusinessPartner,
SalesOrderHeader._Status
}
CDS rule: Remember to double-maintain the annotations that have the VIEW scope. In CDS views, only the annotations with ELEMENT and ASSIOCIATION scope are inherited from the business object view.
@UI.lineItem.position: 50
@UI.identification: [{
position: 50
}]
@OData: {
publish: true
}
@AbapCatalog.sqlViewName: 'ZCSOI'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Items Consumption View'
@VDM.viewType: #CONSUMPTION
@Metadata: {
allowExtensions: true
}
@ObjectModel: {
semanticKey:['salesorder', 'salesorderitem'],
createEnabled: true,
deleteEnabled: true,
updateEnabled: true
}
define view ZC_SalesOrderItems
as select from ZI_SalesOrderItems as Items
association [1..1] to ZC_SalesOrdersHead as _header on _header.salesorder = $projection.salesorder
{
@UI.hidden: true
key Items.salesorder,
@UI.identification.position: 10
@UI.lineItem.position: 10
key Items.salesorderitem,
@UI.identification.position: 20
@UI.lineItem.position: 20
Items.product,
@UI.identification.position: 30
@UI.lineItem.position: 30
Items.grossamount,
@UI.lineItem.label: 'Currency'
@UI.hidden: true
Items.currencycode,
@UI.lineItem.label: 'Quantity'
@UI.lineItem.position: 50
@UI.identification: [{
position: 50,
label: 'Quantity'
}]
Items.quantity,
@ObjectModel: {
association: {
type: [ #TO_COMPOSITION_PARENT, #TO_COMPOSITION_ROOT ]
}
}
_header,
Items._product,
Items._currency
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
11 | |
11 | |
8 | |
7 | |
5 | |
4 | |
4 | |
4 | |
3 |