Fiori-like Purchase Order Approval with OData – Part I
I write this blog with two purposes. First, as a personal objective to streamline my knowledge, and secondly to make sure this new SAP technology is accessible to anyone with the will to learn new stuff. The document will be divided in two sections:
- Part 1 – Backend Logic (ABAP) + SAP Gateway
- Part 2 – SAPUI5 Frontend
I know there is an Purchase Order approval example that ships with SAPUI5 SDK, but this goes step by step, connects to a real SAP system and doesn’t require workflow to be set up, all in order to minimize your reasons to procrastinate . The only functional requirement on the MM side, is that people can approve purchase orders using ME28/ME29N. So let’s get going.
Backend Logic (ABAP)
The backend logic will support two-way communication. The mobile app retrives all the documents that require approval by the logged user, and it will send approval/rejection data to the back-end. The backend logic news three objects (classes):
- Purchase Order
- Purchase Order Item
For the purpose of the demo, we’ll use custom developed classes. The most important one, as far as business logic is the Purchase Order, so let’s create a class Z_MM_PO with the methods:
- GET_PENDING_APPROVALS – Static Public Method returns a table of Z_MM_PO objects;
- SET_APPROVAL – Instance Public Method with no parameter, returns a table of error messages;
- GET_ITENS – Instance Public Method, returns a table of Z_MM_POITEM;
- GET_SUPPLIER – Instance Public Method, returns an instance of Z_MM_SUPPLIER.
The more complex one is GET_PENDING_APPROVALS. In order to keep user input to a minimum I use authorizations to check which codes the user can release, and then check documents for each of these codes. Some of the code is inspired by ME28 (too bad SAP encapsulation is so poor in these older reports). I could use workflow like the standard app does, but many customers don’t use standard workflow to manage approvals, so this will simplify things.
The full code for each of the classes/methods is here. As for the attributes and constructor for each class leave them bare for now, certain attributes will be used in the following Gateway section.
For this part of the demo I assume that you have SAP Gateway configured in your system (if you don’t, check here), and that you have installed Eclipse with SAPUI5 on your computer (If you haven’t, check here).
You can create your data model directly in SAP, but I prefer to the Eclipse OData Modeler. It’s more visual, and easy to import in SAP.
Start by creating a new OData project: New -> OData Development -> Service Implementation Project. I name the project “POApproval” and check the “Create OData file manually”.
After creating the project, I right-click the project folder, choose “New”, “Other” and then “OData Model”. I create a “Blank OData Model” and name it “POApproval”.
The editor opens up, and now I can create my entities. Like described in the “Backend section” I will create three entities: Purchase Order, Purchase Order Item and Supplier. Then I create single associations between the Purchase Order and the other two entities (one PO has multiple itens and one supplier).
New I add the attributes for each of the entities:
For the purpose of this demo, I’ll export the OData model to a file so I can import it in SAP system. Right click the POApproval.odata in the Project Explorer, and select “Export”. Choose OData Model, format “OData V2 SAP Specific” and a file name. Logon to your SAP Gateway system, go to SEGW transaction, and create a new project called “ZPOAPPROVAL”.
Open the project, and right-click “Data Model”. Then choose “Import”, e select the file you exported in Eclipse.
Note: As far as I know you can’t define a 1 to 1 navigation relation in Eclipse. To correct this, go to Data Model -> Associations, and change Dependent Entity Cardinality to 1.
Now that the model has been imported and the relation corrected, we are going to generate our classes, so go to Project -> Generate.
Leave the defaut names, and press “Enter”. After generation, open the “Runtime Objects” folder and you see the generated classes. The one we are going to change is the Data Provider “ZCL_ZPOAPPROVAL_DPC_EXT” because we need to tell the model how to retrieve the data.
All customer changes are made to the _EXT files, don’t ever change the classes without _EXT because they are automatically generated and you will lose all changes if you regenerate the model.
If you enter the class you will see that it has CRUD methods for each entity. For example for the Purchase Order SAP created:
You will have to implement the code for each of the relevant operations and tell the model that some operations (like CREATE or DELETE) are not valid (optional, but recommended).
Let’s start by creating the PURCHASEORDERSET_GET_ENTITYSET method. Enter the class in edit mode and choose “Redefine” (remember this class inherits from a superclass). Then, use the code store here (the code has comments so I hope you understand, any questions use the comments below and I’ll try to elaborate).
After defining the code, check the operations for each field. In SEGW go to Data Model -> Entity Types -> PurchaseOrder -> Properties. Here make sure none of the fields is creatable, only the approval field is updatable and nothing can be deleted. I also define that we can only filter the model using the fields “PurchaseOrderID”, “date” and “totalValue”.
Do this for all entities, and then publish the service. Click “Service Maintenance”, choose GW_HUB and then “Register”. Select your package, and press “Enter”.
Now you shoud be able to enter the url
Now redefine the rest of the required methods, for all three entities to finalize the OData Model.
Before you move on to the SAPUI5 application I highly suggest you read the blog Building SAP Fiori-like UIs with SAPUI5 in 10 Exercises. The final application is based on the code of these exercises, so it will be much easier to understand.