📜 ⬆️ ⬇️

Integration with SAP ERP, for example with Django-python, using the oData (rest) protocol

Good afternoon, Habr!

The topic of integration of large systems like SAP with small but more flexible has always been interesting, so to say take the best of both.

In particular, in my example, the integration of SAP ERP with Django will be described.
')

Task


Because of the many different control systems introduced by our beloved state: Egais, Mercury and many other things, many companies began to adapt their heavy, and to say the least, sluggish systems (for large companies) to new conditions. I won’t say in which I adapted in particular, but the idea was always spinning in my head - Create a single tracking system of everything based on a separate platform.

Facilities


Having chosen which tools to take, I chose not very long: Python programming language - due to the abundance of libraries with everything and everything, the Django platform, don't ask why Django, but not Flask or Odoo. I already took Odoo for the platform and wanted to study one of these, I took the first one, well, I don’t know why, probably because of the greater simplicity. ERP system for SAP development; well, I didn’t have much choice here, because I work in a company as an SAP integrator, so I have the knowledge and access to the sandboxes of this system, so that I can safely do my job with all the conditions.

Frontend django


The first thing I started with was to formulate a specific task and painted it on a piece of paper, in general I advise everyone to code, describe the process, and it is VERY important if you change it on the go, change it in the description too.

Here is the first VERY rude version of the program description.
Outgoing process

1) Outbound delivery is created

2) With the passage of pallets through the gate - Automatic work and semi-automatic work

a. Automatic operation / When the pallet passes through the gate, the program requests the RFC in the WMS system for information about what the delivery is, its number and sends the identification response to the delivery back to the WMS system (possibly confirming the warehouse tasks (tasks for the equipment) on this pallet and all attachments). Also checks all excise stamps with information in the WMS system.

b. Semi-automatic operation / The operator enters the delivery number / machine in the gate system and drives the pallets through the gate, the gate system for each pallet sends a request to the WMS system for checking excise stamps inside.

3) Sent the composition of the delivery in the accounting system

Inbound process

1) Inbound delivery is created

2) Pallet passage through the gate

3) A request is sent to the accounting system about the composition of the acceptance to the current warehouse

4) The internal composition of the pallet of excise stamps is checked on the basis of this accounting system.

5) A signal is sent to the WMS system to unload the pallets.

Required tables :

Goal:
Identifier;
Stock:
Description.
Posting Message :

Title:
Time, system, warehouse number, gate ID.
Position:
Excise stamp, time of registration, binding to the title
ERP message about the composition (inbound delivery)

Title:
Time, system, delivery number,
Position:
Material, excise stamp, pallet number (if any)

Aggregated message (based on data from ERP) :

Title:

Time, system, warehouse number, gate identifier, delivery number from Accounting system, Direction indication (Inbound outbound), Verification script indication, machine number, warehouse gate number,

Position: Excise stamp, pallet number (opt), material (opt), delivery number, car number, position number in the document, batch (opt), packaging (opt)
Next, I began to learn Django and draw the process and schema of the database.
As it turned out in Django, creating table models is very easy and convenient, it looks like this:

class SapOptions(models.Model): name = models.CharField(verbose_name=' ', max_length=50) baseurl = models.CharField(max_length=500, verbose_name='Url  ', help_text = 'URL  ,  ,  :"https://moses1005:44300/sap/opu/odata/sap/ZLS_SUPPLYCHAIN_SRV/"')#  URL sapset = models.CharField(default='Enter Sapset', max_length=100, verbose_name=' ()') mandt = models.CharField(max_length=3, verbose_name='') user = models.CharField(max_length=15, verbose_name='       ') passwd = models.CharField(max_length=15, verbose_name='') verify = models.BooleanField(default=False, help_text = '   ') def __str__(self): return ': '+self.name + ',  : '+self.mandt class Gates(models.Model): from mainAPP.sap_connector import get_lgorts_fromsap ident = models.CharField(verbose_name='', max_length=10, help_text='',unique=True) wh = models.CharField(verbose_name='  ', default='',max_length=10, help_text='   WMS') help = models.CharField(verbose_name='', default='',max_length= 500,help_text=' , ,  ,   ') try: lgorts = get_lgorts_fromsap() except: lgorts = [('No Connect', 'No Connect'),] lgort = models.CharField(verbose_name='',default='0000', max_length=20, choices=lgorts) def __str__(self): return self.ident +' : '+self.wh+' : '+self.help 

After that, I already understood how to pull reference books from SAP, so that the integration seemed to be completely “seamless,” the key word “seemed”, but more on that later.

So, after studying Django (I killed a few nights for it), I wrote an interface for entering information and then sending it to SAP ERP.

The first screen for entering acceptance information is as follows:




Also, the interface is adapted for a mobile terminal (TSD)



The fields are made in such a way that after each pressing ENTER, the cursor jumped to the next input field, so that it would be convenient to scan all the information from TTN, Gate, Pallet.

Then, after scanning the last field or clicking “Save”, the screen switches to the dialog for entering the identifiers of each item:



Fields:

  1. This is the screen of the list of identifiers that were sent by the EGAIS system itself, where the Reds are not yet scanned identifiers, Yellow, these are the identifiers that were scanned, but in the message of the Unified State Automated Information System there were none, and they were green, they were sent by the Unified State Automated Information System
  2. Entering identifiers, here is also the “+” button, which is needed for the appearance of another field, etc.
  3. Displays error messages, if any.

Integration implementation:


For integration from Django, everything is understandable “rest” is easy to implement, but from SAP ERP, I had to read a little).

So, how this is done, as it turns out is not very difficult

1) It is necessary to create an integration class for implementation, respectively a development package for it. This is done in the SEGW transaction.



2) After creating the class, you need to determine the Data Model, there are several options, create your own fields, or click on the table from SAP. This means that before creating a data model for integration, you need to create a table for data, this is done in transaction SE11 and how to do this can be found on the Internet. So, we like the structure,



I like the table-structure I created



3) This is what the work we have done looks like:



Click “Generate”. The class has generated the structure necessary for the integration, and we will work with it.

4) Next, in our Service implementation tab, our structure appears with all the methods available to it, in particular:

a. Create - A method for creating an entry in our table from the data sent from outside
b. Delete- Method for deleting a record by id
c. GetEntity - Single Entry Request Method
d. GetEntitySet - Method for retrieving multiple records by criteria
e. Update - method of changing the record
In fact, all these methods are fairly abstract, but there are of course differences

5) After the class is generated, we create a list of classes in the Runtime Artifacts branch, select the one that has the DPC_EXT at the end


Double click to get into the class itself.

6) After getting into the list of class methods, at the end you see a list of all methods, be sure to redefine it, otherwise after another data model change, everything will be erased, I ran into it, it was insulting ...


For example, I will show the implementation of the Create method



It's very simple, IT_KEY_TAB is sent to the input, and based on this data, we implement some actions, in this code, a normal record in the table, or an error output, which will then be transmitted to Django. The output of the successful creation is written to the structure ER_ENTITY.

7) We test our interface in transaction / IWFND / MAINT_SERVICE, such a long one. Go to it, find our class created and click on “SAP Gateway Client”



As a matter of fact, we can see the EMULATOR GET \ POST \ PUT \ DELETE web of Requests, only from SAP,

PS You can test the created service in anything, I test it in the postman program



This is the get request, “GetEntitySet”
/ sap / opu / odata / sap / ZLS_SUPPLYCHAIN_SRV / ZLS_INBOUND_HEADSet? $ format = json
Where:
/ ZLS_SUPPLYCHAIN_SRV / - This is our created class
/ ZLS_INBOUND_HEADSet is the data model we created,
format = json is the format of the data that we receive, the choice of xml or json, I choose json, because that is why it’s more convenient for me.

8) Similarly, we write methods

What we have created a front on Django, created an interface on the SAP side
Now we need to revive all this, and it is on the Django side that we write methods:

1) The method of creating a session, in order to log in, get scrf-token and already further
pull the necessary information from the database on our configured interface or create a new
record To do this, create a separate file in Django, I called it Sap_connector.py and described
in it the main methods.

 def sap_createSession(): #     oDATA from scanner.models import SapOptions #   SAP sap_opt = SapOptions.objects.all()[0] #       s = requests.Session() s.headers.update({'Connection': 'keep-alive', 'X-CSRF-TOKEN': 'Fetch'}) auth = (sap_opt.user, sap_opt.passwd) try: r = s.get(sap_opt.baseurl, auth=auth,verify=sap_opt.verify) except: message = "    %s %s"%(sap_opt.mandt, sap_opt.name) return ('NO TOKEN', 'NoSession', message) token = r.headers['x-csrf-token'] session = s sess = (token, session, None) return sess 

2) Verification method of delivery to SAP ERP

 def sap_delivery_verify(token, session, delivery): #      ERP from scanner.models import SapOptions, Gates sap_opt = SapOptions.objects.all()[0] s = session format = '?$format=json' set = 'likpSet' url = sap_opt.baseurl + set + "('"+delivery+"')"+format headers = {'Content-type': 'application/json;charset=utf-8', 'X-CSRF-TOKEN': token} #      auth = (sap_opt.user, sap_opt.passwd) # auth get = s.get(url, headers=headers, auth=auth,verify=sap_opt.verify)#   if get.status_code ==200: delivery_out = json.loads(get.text).get('d').get('Vbeln') return (True, 'OK') else: error_text = json.loads(get.text).get('error').get('message').get('value') return (False, error_text) 

3) SAP Warehouse Integration Method with Django

 def get_lgorts_fromsap(): from scanner.models import SapOptions session = sap_createSession() #   token = session[0] session = session[1] sap_opt = SapOptions.objects.all()[0] #   s = session format = '?$format=json' set = 't001lSet' url = sap_opt.baseurl + set +format headers = {'Content-type': 'application/json;charset=utf-8', 'X-CSRF-TOKEN': token} #      auth = (sap_opt.user, sap_opt.passwd) # auth get = s.get(url, headers=headers, auth=auth,verify=sap_opt.verify)#   jdata = json.loads(get.text) lgorts = [] for l in jdata.get('d').get('results'): l.get('lgort') lgorts.append((l.get('Lgort'),l.get('Lgort'))) return lgorts 

And its second part in the models part:

 class Gates(models.Model): from mainAPP.sap_connector import get_lgorts_fromsap ident = models.CharField(verbose_name='', max_length=10, help_text='',unique=True) wh = models.CharField(verbose_name='  ', default='',max_length=10, help_text='   WMS') help = models.CharField(verbose_name='', default='',max_length= 500,help_text=' , ,  ,   ') try: #   SAP lgorts = get_lgorts_fromsap() except: lgorts = [('No Connect', 'No Connect'),] lgort = models.CharField(verbose_name='',default='0000', max_length=20, choices=lgorts) def __str__(self): return self.ident +' : '+self.wh+' : '+self.help 

The integration looks like this: when I create a new warehouse in the Django settings, then in the warehouse field, the system directly displays the warehouses from SAP ERP that are currently created there.



4) Method for creating a new entry in SAP ERP

 def sap_connect(token, session, data): from scanner.models import SapOptions, Gates #      SAP ERP sap_opt = SapOptions.objects.all()[0] s = session delivery = data.get('delivery') url = sap_opt.baseurl + sap_opt.sapset #  URL +    headers = {'Content-type': 'application/json;charset=utf-8', 'X-CSRF-TOKEN': token} #      auth = (sap_opt.user, sap_opt.passwd) # auth data =json.dumps({"d":{ "Mandt": sap_opt.mandt, "Lgort": Gates.objects.get(id=data.get('gates')).wh, "Vbeln":data.get('delivery'), "Mark": data.get('mark'), "Matnr": "", "Posnr": "", "Mbl": "", "InbDicid":"AAAAAAAAAAAAAAAAAAAAAA==", "DocExt": data.get('ttn'), "Exidv": data.get('pack') }}) try: r2 = s.post(url, data=data, headers=headers, auth=auth) except: return (False, '   ') if r2.status_code ==201: print(' %s   '%(delivery)) return (True, '  %s : '%delivery) else: print('  %s   '%(delivery)) text = r2.text SO = soup(text) s = SO.find_all("message")[0].text return (False, s) 

In fact, we simply make a POST request and write data there in json format.

Conclusion


We have created a program integrated with SAP ERP, with a simple work scenario,
A car arrives, we enter information for each pallet in the interface, the program checks if all the data is entered correctly, and provides information on what should be and what has already been entered. After entering the data, it issues a report on the work done and sends the data to SAP ERP. Also, this interface is adapted from mobile data entry interfaces, which is important for warehouses with data collection terminals (TSD). After transferring the data to the ERP system, it also saves all the data, to which warehouse, which identifier came, which type of identifier, who accepted, and so on.

As a result, we have a program for processing incoming and outgoing product identifiers in the company, while 90% of all work is carried out in an external system integrated with the main system.

In the future, it needs to be refined to maintain incoming lots, serial numbers and other things, and even more closely integrate with SAP, for example, create a receipt receipt from this interface, well, this is already a thought for development :)

PS I didn’t paint the ABAP or python-django code of this working solution, didn’t paint the Django or html templates, but concentrated on integration with SAP ERP to show that creating a module for connecting to such a large system as SAP is not difficult and It took me to such a system, if I included the study of Django in about 4 evenings.

Thank you all for your attention, I will be grateful for constructive criticism!

Source: https://habr.com/ru/post/426611/


All Articles