{"id":512,"date":"2020-06-29T12:21:20","date_gmt":"2020-06-29T10:21:20","guid":{"rendered":"https:\/\/jonathanpapa.com\/blog\/?p=512"},"modified":"2022-04-30T09:22:35","modified_gmt":"2022-04-30T07:22:35","slug":"custom-b1web-portal","status":"publish","type":"post","link":"https:\/\/jonathanpapa.com\/blog\/2020\/06\/29\/custom-b1web-portal\/","title":{"rendered":"Tailor-made SAP B1 Web Portal for a customer in Luxembourg"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"512\" class=\"elementor elementor-512\">\n\t\t\t\t\t\t<div class=\"elementor-inner\">\n\t\t\t\t<div class=\"elementor-section-wrap\">\n\t\t\t\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-933b514 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"933b514\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t\t\t<div class=\"elementor-row\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-d329258\" data-id=\"d329258\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-column-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-6618124 elementor-widget elementor-widget-heading\" data-id=\"6618124\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Introduction<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-347915e elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"347915e\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t\t\t<div class=\"elementor-row\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-28b3308\" data-id=\"28b3308\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-column-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-47fe5cb elementor-widget elementor-widget-text-editor\" data-id=\"47fe5cb\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p>A few months ago, I got involved in an <strong><em>SAP Business One<\/em><\/strong> project for an hotel in&nbsp;<strong><em>Luxembourg <img class=\"emoji\" role=\"img\" draggable=\"false\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/12.0.0-1\/svg\/1f1f1-1f1fa.svg\" alt=\"\ud83c\uddf1\ud83c\uddfa\">. <\/em><\/strong>Together, with a local SAP partner that took care of the functional analysis and provided me with the requirements, we were able to deliver a tailor-made solution for the customer.<\/p>\n<p>The aim was to build a <em><strong>web portal<\/strong><\/em> to manage the stock of the hotel restaurant that would eventually be used by people without any knowledge of <em><strong>SAP<\/strong><\/em>. The users would be able to create purchase orders, purchase requests and inventory transfers amongst several other features that would enhance the standard B1 behavior, making it both <strong>easier<\/strong> and <strong>faster<\/strong> for employees to perform their daily tasks.<\/p>\n<p><em><strong>SAP Business One<\/strong><\/em> client is indeed full of features which can be overwhelming even after years of use. The portal was thought to shorten this list of features, said otherwise, to keep it simple and targeted for a set of employees. Two different positionings, as seen in the chart below:<\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ad869ba elementor-widget elementor-widget-image\" data-id=\"ad869ba\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-image\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/Untitled-Diagram.png\" data-elementor-open-lightbox=\"yes\" e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6NTk0LCJ1cmwiOiJodHRwczpcL1wvam9uYXRoYW5wYXBhLmNvbVwvYmxvZ1wvd3AtY29udGVudFwvdXBsb2Fkc1wvMjAyMFwvMDZcL1VudGl0bGVkLURpYWdyYW0ucG5nIn0%3D\">\n\t\t\t\t\t\t\t<img width=\"812\" height=\"240\" src=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/Untitled-Diagram.png\" class=\"attachment-large size-large\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/Untitled-Diagram.png 871w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/Untitled-Diagram-300x89.png 300w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/Untitled-Diagram-768x227.png 768w\" sizes=\"(max-width: 812px) 100vw, 812px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3cc2e97 elementor-widget elementor-widget-text-editor\" data-id=\"3cc2e97\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p>In this article, I would like to take you through the different steps and thought process that I had during the making of this web application. I will also discuss about the several possibilities you have when designing a custom solution on top of\u00a0<strong><em>SAP Business One\u00a0<\/em><\/strong>(see\u00a0<a href=\"https:\/\/jonathanpapa.com\/blog\/?p=512&amp;elementor-preview=512&amp;ver=1599832398#customizingB1\"><strong><em>Customizing SAP B1: Why and how?<\/em><\/strong><\/a>).<\/p><p>It is good to write about it but better to show it, there are several screenshots of the application throughout the article (<em>data displayed is from a B1 demo database<\/em>). So you&rsquo;ll get a glimpse of the portal! Also make sure you check out the<em><strong>\u00a0<a href=\"https:\/\/jonathanpapa.com\/blog\/?p=512&amp;elementor-preview=512&amp;ver=1599832398#gallery\">gallery<\/a><\/strong><\/em>\u00a0at the bottom of the page for more screenshots \ud83e\uddd0.\u00a0<\/p><p>This article is indeed technical but will also focus on general concepts around SAP B1 customization. If you&rsquo;re curious about this topic or simply looking for inspiration for your project, this may be a good starting point? \ud83d\ude09<\/p><p>Alright, let&rsquo;s get down to it! \ud83d\udc40<\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-c506603 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"c506603\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t\t\t<div class=\"elementor-row\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-9c56ec2\" data-id=\"9c56ec2\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-column-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-5719fc2 elementor-widget elementor-widget-menu-anchor\" data-id=\"5719fc2\" data-element_type=\"widget\" data-widget_type=\"menu-anchor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div id=\"customizingB1\" class=\"elementor-menu-anchor\"><\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b791c7d elementor-widget elementor-widget-heading\" data-id=\"b791c7d\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Customizing SAP B1: Why and how?<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-634d049 elementor-widget elementor-widget-text-editor\" data-id=\"634d049\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p>Customization in SAP B1 comes in different flavors and depends on the complexity of your project:<\/p><ul><li><em><strong>Standard<\/strong> <\/em>or <strong><em>Light<\/em><\/strong> customization through the creation of <strong>U<\/strong>ser-<strong>D<\/strong>efined <strong>F<\/strong>ields (<em><strong>UDF<\/strong><\/em>), <strong>U<\/strong>ser-<strong>D<\/strong>efined <strong>T<\/strong>ables (<em><strong>UDT<\/strong><\/em>) and <strong>U<\/strong>ser-<strong>D<\/strong>efined <strong>O<\/strong>bjects (<em><strong>UDO<\/strong><\/em>) which allows you to extend the data-structure of the ERP.<\/li><li>Modifying the <strong>T<\/strong>ransaction <strong>N<\/strong>otification (<em><strong>TN<\/strong><\/em>) which is an SQL procedure that is triggered everytime a business object (let&rsquo;s say an item or an order) is added, updated or deleted. This allows you to add your own checks on top of the B1 logic.<\/li><li>Add-on development using the UI-API to build custom screens.<ul><li>Some add-ons also allow you to customize the screens without the need to code anything<\/li><\/ul><\/li><\/ul><p>It is very common to see these three components interacting with each other in order to achieve the desired enhancements of the solution. Historically, people would customize SAP exactly like that.<\/p><p>Today, with the addition of the <a href=\"#b1SL\">Service Layer<\/a>, which is a REST API. It is now very easy to interact with the ERP from the outside. Coupled with <a href=\"#sapui5\">SAPUI5<\/a> for the UI, SAP provides two technologies that blend nicely together.<\/p><p>Think of it as an outside add-on that you can use without the need of having an opened B1 Client, which is pretty convenient.\u00a0<\/p><p><span style=\"text-align: justify;\">Now, we all know that an ERP never comes out of the box for a customer and that it needs to be rightly setup and very often customized to fit to the business requirements. This leads to the creation of many rules that need to be implemented on top of the ERP standard rules. But how exactly can you add them?<\/span><\/p><p><span style=\"text-align: justify;\">In our case, the custom business rules were added inside an API that is eventually used by the portal itself.<\/span><\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-69d437e elementor-widget elementor-widget-image\" data-id=\"69d437e\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-image\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/Untitled-Diagram-2.png\" data-elementor-open-lightbox=\"yes\" e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6NTk2LCJ1cmwiOiJodHRwczpcL1wvam9uYXRoYW5wYXBhLmNvbVwvYmxvZ1wvd3AtY29udGVudFwvdXBsb2Fkc1wvMjAyMFwvMDZcL1VudGl0bGVkLURpYWdyYW0tMi5wbmcifQ%3D%3D\">\n\t\t\t\t\t\t\t<img width=\"492\" height=\"442\" src=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/Untitled-Diagram-2.png\" class=\"attachment-large size-large\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/Untitled-Diagram-2.png 492w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/Untitled-Diagram-2-300x270.png 300w\" sizes=\"(max-width: 492px) 100vw, 492px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-de1c3f0 elementor-widget elementor-widget-text-editor\" data-id=\"de1c3f0\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p>Why is that a good thing? Because it provides one easily accessible entry point for all potential applications that would want to interact with the ERP with the same rules and constraints as the ones we implemented for the portal.<\/p><p>In this scenario, a request goes first through our custom API and undergoes custom checks before being forwarded to the Service Layer which abides to B1 standard rules &amp; checks.<\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-877cf38 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"877cf38\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t\t\t<div class=\"elementor-row\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-e25f5d5\" data-id=\"e25f5d5\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-column-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-ad114f9 elementor-widget elementor-widget-heading\" data-id=\"ad114f9\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">The Portal<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-88fb898 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"88fb898\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t\t\t<div class=\"elementor-row\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-45bd38c\" data-id=\"45bd38c\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-column-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-86d0428 elementor-widget elementor-widget-text-editor\" data-id=\"86d0428\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p style=\"font-size: 16px; text-align: justify;\">As mentioned in the introduction, the goal was to create a portal where users would be able to create documents such as purchase orders, purchase requests or inventory transfers.<\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-646d5f5 elementor-widget elementor-widget-text-editor\" data-id=\"646d5f5\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p style=\"text-align: justify;\"><span style=\"font-style: inherit; font-weight: inherit;\">Since B1 screens can be overwhelming at first, we wanted to make it as easy as possible for the user to create the desired documents but in the same way, to keep the basic features such as the possibility to add text lines.<\/span><\/p><p style=\"text-align: justify;\">You may wonder why such a portal was built for something as standard as creating and modifying documents. The answer is simple: if the global behavior was to be kept as standard as possible, the solution would also come with a great number of custom business rules, specific to the hotel business.<\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e0c8d80 elementor-widget elementor-widget-image\" data-id=\"e0c8d80\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-image\">\n\t\t\t\t\t\t\t\t\t<figure class=\"wp-caption\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/07\/add-PO2.gif\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Adding a Purchase Order\" e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6NTI2LCJ1cmwiOiJodHRwczpcL1wvam9uYXRoYW5wYXBhLmNvbVwvYmxvZ1wvd3AtY29udGVudFwvdXBsb2Fkc1wvMjAyMFwvMDdcL2FkZC1QTzIuZ2lmIn0%3D\">\n\t\t\t\t\t\t\t<img width=\"1328\" height=\"740\" src=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/07\/add-PO2.gif\" class=\"attachment-full size-full\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t<figcaption class=\"widget-image-caption wp-caption-text\">Adding a Purchase Order with the portal<\/figcaption>\n\t\t\t\t\t\t\t\t\t\t<\/figure>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-11e211f elementor-invisible elementor-widget elementor-widget-text-editor\" data-id=\"11e211f\" data-element_type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;pulse&quot;}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p>Make sure you also check the <a href=\"#gallery-anchor\">Gallery section<\/a>\u00a0(<em>click to access<\/em>) at the bottom of this page for more screenshots!<\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3a1c6bd elementor-widget elementor-widget-text-editor\" data-id=\"3a1c6bd\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p>Let us now take at a look at the technology stack that was used to build the portal!<\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-8165a8d elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"8165a8d\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t\t\t<div class=\"elementor-row\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-66709c0\" data-id=\"66709c0\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-column-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-a8c378b elementor-widget elementor-widget-menu-anchor\" data-id=\"a8c378b\" data-element_type=\"widget\" data-widget_type=\"menu-anchor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div id=\"sapui5\" class=\"elementor-menu-anchor\"><\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-95abace elementor-widget elementor-widget-heading\" data-id=\"95abace\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">SAPUI5<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-895bb4d elementor-widget elementor-widget-text-editor\" data-id=\"895bb4d\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p style=\"margin: 0in 0in 16.8pt; text-align: justify; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial;\"><span style=\"font-family: Lato, sans-serif;\">The application UI was built using SAPUI5.<\/span><\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ef0911b elementor-widget elementor-widget-image\" data-id=\"ef0911b\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-image\">\n\t\t\t\t\t\t\t\t\t\t\t\t<img width=\"300\" height=\"105\" src=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/sapui5-300x105.png\" class=\"attachment-medium size-medium\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/sapui5-300x105.png 300w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/sapui5-1024x358.png 1024w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/sapui5-768x268.png 768w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/sapui5.png 1099w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-815be36 elementor-widget elementor-widget-text-editor\" data-id=\"815be36\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p>There are two main reasons for that:<\/p>\n<ul>\n<li>The portal was thought to be used alongside the B1 client. And since the B1 client for HANA comes with a UI5 look, this blended nicely with the ERP.<\/li>\n<li>Designing screens can be time-consuming. And that is precisely one of the strengths of UI5. The framework comes with a very wide sets of controls that you only need to provide data to (usually as JSON or XML if you\u2019re consuming OData services). The controls are then rendered accordingly in HTML. The framework implements what\u2019s referred as \u201cFiori guidelines\u201d which are a set of UX rules to provide the user with a nice, friendly and clear UI.<\/li>\n<\/ul>\n<p>In a nutshell, the developer can focus on his code rather than on the UI itself.<\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-e3b2f69 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"e3b2f69\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t\t\t<div class=\"elementor-row\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-128f197\" data-id=\"128f197\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-column-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-5e6d205 elementor-widget elementor-widget-menu-anchor\" data-id=\"5e6d205\" data-element_type=\"widget\" data-widget_type=\"menu-anchor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div id=\"b1SL\" class=\"elementor-menu-anchor\"><\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ffa68c3 elementor-widget elementor-widget-heading\" data-id=\"ffa68c3\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Service Layer<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e97e8d4 elementor-widget elementor-widget-text-editor\" data-id=\"e97e8d4\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p style=\"text-align: justify; background: white; vertical-align: baseline; margin: 0in 0in 16.8pt 0in;\"><span style=\"font-family: 'Lato',sans-serif; color: #7a7a7a;\">Luckily for me, this was a brand-new\u00a0<strong><i><span style=\"font-family: 'Lato',sans-serif;\">SAP Business One<\/span><\/i><\/strong>\u00a0solution and therefore, the customer opted for an\u00a0<strong><i><span style=\"font-family: 'Lato',sans-serif;\">SAP HANA<\/span><\/i><\/strong>\u00a0version, giving me access to integration features that do not (yet) exist in the MSSQL version, one of them being the <b><i>Service Layer<\/i><\/b>.<\/span><\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-15ba641 elementor-widget elementor-widget-image\" data-id=\"15ba641\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-image\">\n\t\t\t\t\t\t\t\t\t\t\t\t<img width=\"300\" height=\"102\" src=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/b1forhana-300x102.png\" class=\"attachment-medium size-medium\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/b1forhana-300x102.png 300w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/b1forhana-1024x348.png 1024w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/b1forhana-768x261.png 768w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/b1forhana-1536x522.png 1536w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/b1forhana.png 1894w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-aebaef1 elementor-widget elementor-widget-text-editor\" data-id=\"aebaef1\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p>I&rsquo;ve already written some stuff about the <strong>Service Layer<\/strong> in my previous articles but just to sum it up, it is an out-of-the-box REST API provided by SAP that allows you to <strong>C<\/strong>reate, <span style=\"font-family: 'Lato',sans-serif; color: #7a7a7a;\"><strong>R<\/strong>ead, <strong>U<\/strong>pdate and <strong>D<\/strong>elete (when possible) business objects (such as invoices, business partners, items etc.\u2026) in the ERP. <\/span><\/p><p><span style=\"font-family: 'Lato',sans-serif; color: #7a7a7a;\">Since we\u2019re talking about creating a web-application, you can easily understand that a REST API is perfectly fitted for this kind of development. \ud83d\ude0a<\/span><\/p><p style=\"text-align: justify; background: white; vertical-align: baseline; margin: 0in 0in 16.8pt 0in;\"><span style=\"font-family: 'Lato',sans-serif; color: #7a7a7a;\">At the moment, the <strong>Service Layer<\/strong> is only available for the <strong>HANA<\/strong> version. It&rsquo;s\u00a0 undoubtedly a huge lack in the <strong>MSSQL<\/strong> version because it closes the doors for many integration possibilities.<\/span><\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-5f7d90e elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"5f7d90e\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t\t\t<div class=\"elementor-row\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-85f23f8\" data-id=\"85f23f8\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-column-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-dec1340 elementor-widget elementor-widget-heading\" data-id=\"dec1340\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">ASP .NET Core<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b1773fd elementor-widget elementor-widget-text-editor\" data-id=\"b1773fd\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p>In the previous sections, we&rsquo;ve discussed the general concept of customizing SAP B1 (see section <em><strong><a href=\"#customizingB1\">Customizing SAP B1: Why and how?<\/a><\/strong><\/em>) and we&rsquo;ve seen that we often needed a layer on top of the B1 logic to implement additional rules<span style=\"font-style: inherit; font-weight: inherit; color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family );\">.<\/span><\/p><p>In this case, these so-called custom rules were written inside an <strong>ASP .NET Core Web<\/strong> API that is consumed via the SAPUI5 page. The Web API can then forward the request to the Service Layer when data needs to be updated in the B1 system.<\/p><p>Simply put: it&rsquo;s an API calling another API (the service layer).\u00a0<span style=\"font-style: inherit; font-weight: inherit; color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family );\">This concept is represented below:<\/span><\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-174c3ef elementor-widget elementor-widget-image\" data-id=\"174c3ef\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-image\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/archiwebv2.png\" data-elementor-open-lightbox=\"yes\" e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6NTMxLCJ1cmwiOiJodHRwczpcL1wvam9uYXRoYW5wYXBhLmNvbVwvYmxvZ1wvd3AtY29udGVudFwvdXBsb2Fkc1wvMjAyMFwvMDZcL2FyY2hpd2VidjIucG5nIn0%3D\">\n\t\t\t\t\t\t\t<img width=\"812\" height=\"376\" src=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/archiwebv2-1024x474.png\" class=\"attachment-large size-large\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/archiwebv2-1024x474.png 1024w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/archiwebv2-300x139.png 300w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/archiwebv2-768x356.png 768w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/archiwebv2.png 1119w\" sizes=\"(max-width: 812px) 100vw, 812px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-846e44f elementor-widget elementor-widget-text-editor\" data-id=\"846e44f\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p>From left to right:<\/p><ul><li><strong>SAPUI5<\/strong><ul><li>Sends AJAX requests to the ASP .NET Core API<\/li><\/ul><\/li><li><strong>ASP .NET Core<\/strong><ul><li>Processes the request<\/li><li>Performs additional checks<\/li><li>Forwards the request to the Service Layer<\/li><\/ul><\/li><li><strong>Service Layer<\/strong><ul><li>Adds\/Updates a business object in SAP B1<\/li><\/ul><\/li><\/ul><p>As you can see, the UI never queries directly the Service Layer. That is for two main reasons:<\/p><ul><li>First of all, the Service Layer does nothing more than using B1 standard logic to add or update the system, it doesn\u2019t implement any customer-specific logic (except the additional checks you would put in the Transaction Notification).<\/li><li>It would be a security flaw to give access to the Service Layer directly in the UI as the user could forge his own requests to the system without any proper authorization flow. The API also performs additional authorization checks based on the authenticated user.<\/li><\/ul><p>If you\u2019re still up for some good old UML sequence diagram, another representation of this concept is the following:<\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b3b0e28 elementor-widget elementor-widget-image\" data-id=\"b3b0e28\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-image\">\n\t\t\t\t\t\t\t\t\t<figure class=\"wp-caption\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/umlsequence.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Sequence Diagram : Adding a document via the web portal\" e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6NTMyLCJ1cmwiOiJodHRwczpcL1wvam9uYXRoYW5wYXBhLmNvbVwvYmxvZ1wvd3AtY29udGVudFwvdXBsb2Fkc1wvMjAyMFwvMDZcL3VtbHNlcXVlbmNlLnBuZyJ9\">\n\t\t\t\t\t\t\t<img width=\"788\" height=\"475\" src=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/umlsequence.png\" class=\"attachment-large size-large\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/umlsequence.png 788w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/umlsequence-300x181.png 300w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/umlsequence-768x463.png 768w\" sizes=\"(max-width: 788px) 100vw, 788px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t<figcaption class=\"widget-image-caption wp-caption-text\">Sequence Diagram : Adding a document via the web portal<\/figcaption>\n\t\t\t\t\t\t\t\t\t\t<\/figure>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6f6f753 elementor-widget elementor-widget-text-editor\" data-id=\"6f6f753\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p style=\"text-align: justify; background: white; vertical-align: baseline; margin: 0in 0in 16.8pt 0in;\"><span style=\"font-family: 'Lato',sans-serif; color: #7a7a7a;\">This works whenever you need to <b>add<\/b> data into the ERP. You just need to make sure that you automatically renew your Service Layer access token whenever it expires.<\/span><\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-5867746 elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"5867746\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t\t\t<div class=\"elementor-row\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-7f54811\" data-id=\"7f54811\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-column-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-995ca77 elementor-widget elementor-widget-heading\" data-id=\"995ca77\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Fetching data from SAP B1: What I didn\u2019t do<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-467ca54 elementor-widget elementor-widget-text-editor\" data-id=\"467ca54\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p>When it comes to <em><strong>fetching data from the ERP<\/strong><\/em> such as a list of business partners, sales orders, or items, the most straightforward approach would be <em><strong>to open a (pool of) SQL connection(s) to the server<\/strong><\/em> (in this case, the HANA server) and read data out of SQL queries.<\/p><p>We usually don&rsquo;t want to use the Service Layer (or any API in general) for strict reading purpose because:<\/p><ul><li>It is slower than executing SQL Queries<\/li><li>It doesn&rsquo;t expose all the fields. Technical fields for instance aren&rsquo;t returned (such as <em><strong>DocEntry<\/strong> <\/em>of <em><strong>OCRD<\/strong> <\/em>Table), and yes, OCRD Table <em><strong>does<\/strong><\/em> have a <em><strong>DocEntry<\/strong> <\/em>field (I bet you didn&rsquo;t know that, did ya?)<\/li><li>It isn&rsquo;t as flexible as an SQL Query, particularly if you&rsquo;re performing complex filtering operations.<\/li><\/ul><p>So, a common approach would be to have <strong>two communication channels<\/strong>:<\/p><ul><li>One (or a pool of) connection(s) between the <strong>API<\/strong> and the <strong>Database<\/strong> for reading operations.<\/li><li>One connection between the <strong>API<\/strong> and the <strong>Service Layer<\/strong> for writing operations.<\/li><\/ul>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-24d667f elementor-widget elementor-widget-image\" data-id=\"24d667f\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-image\">\n\t\t\t\t\t\t\t\t\t<figure class=\"wp-caption\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/approach.png\" data-elementor-open-lightbox=\"yes\" e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6NTM0LCJ1cmwiOiJodHRwczpcL1wvam9uYXRoYW5wYXBhLmNvbVwvYmxvZ1wvd3AtY29udGVudFwvdXBsb2Fkc1wvMjAyMFwvMDZcL2FwcHJvYWNoLnBuZyJ9\">\n\t\t\t\t\t\t\t<img width=\"812\" height=\"334\" src=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/approach.png\" class=\"attachment-large size-large\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/approach.png 905w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/approach-300x123.png 300w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/approach-768x316.png 768w\" sizes=\"(max-width: 812px) 100vw, 812px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t<figcaption class=\"widget-image-caption wp-caption-text\">A common approach for Read\/Write operations to SAP B1<\/figcaption>\n\t\t\t\t\t\t\t\t\t\t<\/figure>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-adc7fb3 elementor-widget elementor-widget-text-editor\" data-id=\"adc7fb3\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p style=\"margin: 0in 0in 16.8pt; text-align: justify; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial;\"><span style=\"font-family: Lato, sans-serif;\">Nowadays, people tend to use <strong>O<\/strong>bject-<strong>R<\/strong>elational <strong>M<\/strong>apping tools (abbreviated <strong>ORM<\/strong>) to access the data from a database.<\/span><\/p><p style=\"margin: 0in 0in 16.8pt; text-align: justify; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial;\"><span style=\"font-family: Lato, sans-serif;\">If you\u2019re not familiar with the concept of <strong>ORM<\/strong>, just think of it a tool that allows you to transform database rows into in-memory objects (and vice-versa).<\/span><\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4629fa9 elementor-widget elementor-widget-image\" data-id=\"4629fa9\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-image\">\n\t\t\t\t\t\t\t\t\t<figure class=\"wp-caption\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/ORMHANA.png\" data-elementor-open-lightbox=\"yes\" e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6NTM1LCJ1cmwiOiJodHRwczpcL1wvam9uYXRoYW5wYXBhLmNvbVwvYmxvZ1wvd3AtY29udGVudFwvdXBsb2Fkc1wvMjAyMFwvMDZcL09STUhBTkEucG5nIn0%3D\">\n\t\t\t\t\t\t\t<img width=\"677\" height=\"218\" src=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/ORMHANA.png\" class=\"attachment-large size-large\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/ORMHANA.png 677w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/ORMHANA-300x97.png 300w\" sizes=\"(max-width: 677px) 100vw, 677px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t<figcaption class=\"widget-image-caption wp-caption-text\">Using an ORM with SAP Business One: Database-first approach<\/figcaption>\n\t\t\t\t\t\t\t\t\t\t<\/figure>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-063c5c6 elementor-widget elementor-widget-text-editor\" data-id=\"063c5c6\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p>In the example above, a typical use of the ORM would be to fetch a customer along with all of his nested objects, such as his addresses (Table CRD1) and his contact persons (Table OCPR). This can be achieved without writing a single line of SQL.<\/p><p>This is particularly useful when complex operations and checks are applied on the business objects which is the case for this project.<\/p><p>Such a tool greatly increases productivity and drastically reduces development time.<\/p><p>Since we\u2019re working on top of an existing system, some ORMs include a <strong>Database-First approach<\/strong>, which consists in scanning the tables and generating class code to represent them in memory.<\/p><p>The problem with SAP Business One data model is that <strong>it does not include foreign keys at all<\/strong>. So, you basically end up with a bunch of tables that you manually need to link together through joins\u2026 which eventually leads to the same result as writing SQL queries.<\/p><p>I ended up not using this approach but if you still want to build something with an ORM linked to the HANA database, just make sure that you choose Entity Framework 6 over Entity Framework <u>Core<\/u> which is <strong>not<\/strong> compatible with SAP HANA.<\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-439f928 elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"439f928\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t\t\t<div class=\"elementor-row\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-eb36fb9\" data-id=\"eb36fb9\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-column-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-3ba3192 elementor-widget elementor-widget-heading\" data-id=\"3ba3192\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Fetching data from SAP B1: What I did<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d3e5dc0 elementor-widget elementor-widget-text-editor\" data-id=\"d3e5dc0\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p style=\"text-align: justify; background: white; vertical-align: baseline; margin: 0in 0in 16.8pt 0in;\"><span style=\"font-family: 'Lato',sans-serif; color: #7a7a7a;\"><strong>ERPs<\/strong> have become more than just a piece of software in a company, it is often used a central hub for all the services of the company (inventory, sales, purchases, human resources etc&#8230;)<\/span><\/p><p style=\"text-align: justify; background: white; vertical-align: baseline; margin: 0in 0in 16.8pt 0in;\"><span style=\"font-family: 'Lato',sans-serif; color: #7a7a7a;\">Building a window to your <strong>ERP<\/strong> system is not insignificant as it gives access to your data. Extra precautions and analysis need to be done and even more if you\u2019re building an <strong>extranet<\/strong> application or if the current application is likely to be exposed publicly in the future.<\/span><\/p><p style=\"text-align: justify; background: white; vertical-align: baseline; margin: 0in 0in 16.8pt 0in;\"><span style=\"font-family: 'Lato',sans-serif; color: #7a7a7a;\">Having that in mind and knowing that the data structure of <strong>SAP Business One<\/strong> couldn\u2019t be easily manipulated via <strong>ORM<\/strong> (at least, not the way that I wanted), I decided to go for a totally different approach.<\/span><\/p><p style=\"text-align: justify; background: white; vertical-align: baseline; margin: 0in 0in 16.8pt 0in;\"><span style=\"font-family: 'Lato',sans-serif; color: #7a7a7a;\">The idea was to <strong>take the data<\/strong> out of B1, <strong>transform<\/strong> it, and <strong>store<\/strong> it in another database, using, this time, a <strong>code-first approach<\/strong>.<\/span><\/p><p style=\"text-align: justify; background: white; vertical-align: baseline; margin: 0in 0in 16.8pt 0in;\"><span style=\"font-family: 'Lato',sans-serif; color: #7a7a7a;\">When using a <strong>code-first approach<\/strong>, the first step is to <strong>define your model in the code through classes<\/strong> (in our case, C# classes), define the <strong>relations<\/strong> between your different <strong>entities<\/strong>, and let the ORM <strong>translates<\/strong> the <strong>classes<\/strong> and relations into <strong>tables<\/strong> and foreign keys. This is shown in the diagram below:<\/span><\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0f9d35c elementor-widget elementor-widget-image\" data-id=\"0f9d35c\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-image\">\n\t\t\t\t\t\t\t\t\t<figure class=\"wp-caption\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/ormcodefirst-1.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"ormcodefirst\" e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6NTM5LCJ1cmwiOiJodHRwczpcL1wvam9uYXRoYW5wYXBhLmNvbVwvYmxvZ1wvd3AtY29udGVudFwvdXBsb2Fkc1wvMjAyMFwvMDZcL29ybWNvZGVmaXJzdC0xLnBuZyJ9\">\n\t\t\t\t\t\t\t<img width=\"699\" height=\"280\" src=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/ormcodefirst-1.png\" class=\"attachment-medium_large size-medium_large\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/ormcodefirst-1.png 699w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/ormcodefirst-1-300x120.png 300w\" sizes=\"(max-width: 699px) 100vw, 699px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t<figcaption class=\"widget-image-caption wp-caption-text\">Using an ORM with SAP Business One: Code-first approach<\/figcaption>\n\t\t\t\t\t\t\t\t\t\t<\/figure>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a975b6d elementor-widget elementor-widget-text-editor\" data-id=\"a975b6d\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p style=\"text-align: justify; background: white; vertical-align: baseline; margin: 0in 0in 16.8pt 0in;\"><span style=\"font-family: 'Lato',sans-serif; color: #7a7a7a;\">Wow, hold on there! <strong>MariaDb<\/strong>? Where\u2019s <strong>SAP HANA<\/strong>?<\/span><\/p><p style=\"text-align: justify; background: white; vertical-align: baseline; margin: 0in 0in 16.8pt 0in;\"><span style=\"font-family: 'Lato',sans-serif; color: #7a7a7a;\">That\u2019s right, I used a <strong>MariaDb<\/strong> database to store my translated B1 data schema for several reasons: I needed something small, reliable and compatible with the ORM that I chose: <strong>Entity Framework Core<\/strong>!<\/span><\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-726dec2 elementor-widget elementor-widget-image\" data-id=\"726dec2\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-image\">\n\t\t\t\t\t\t\t\t\t\t\t\t<img width=\"300\" height=\"183\" src=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/Entity-Framework-Logo_2colors_Square_RGB-591x360-1-300x183.png\" class=\"attachment-medium size-medium\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/Entity-Framework-Logo_2colors_Square_RGB-591x360-1-300x183.png 300w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/Entity-Framework-Logo_2colors_Square_RGB-591x360-1.png 591w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f52710f elementor-widget elementor-widget-text-editor\" data-id=\"f52710f\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p>You may legitimately ask yourself:<\/p><p><strong>What is the benefit of extracting the structure of SAP Business One to rebuild it later on <\/strong>?<\/p><p>The key thing to understand is that, we\u2019re not necessarily building the <strong>same<\/strong> data structure. It actually has several advantages:<\/p><ul><li>The data structure is created specifically to fit with our business needs. On a conceptual side, it\u2019s possible to create links between entities that we know will be useful. This can fasten both the development and the overall performance of the API.<\/li><\/ul><p>If you\u2019re not convinced, just think about the serial number allocation table (OITR\/ITR1) in SAP Business One and how hectic it can be to link it to the corresponding documents.\u00a0<span style=\"color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ); font-weight: var( --e-global-typography-text-font-weight );\">A tailor-made-data-structure makes it both easier &amp; faster to query data.<\/span><\/p><ul><li>On top of that, it allows you to restrict the data that is made available <strong>outside<\/strong> of the ERP. This is particularly important if you\u2019re thinking about opening the application to the extranet. What\u2019s more, this restriction can be applied at two levels.<ul><li>Let us take as an example the Business Partners table (OCRD). You\u2019re not necessarily exposing the whole set of business partners <strong>and<\/strong> inside of this set, you\u2019re not necessarily exposing all the columns.<\/li><\/ul><\/li><\/ul><p>It comes with two drawbacks:<\/p><ul><li>You need a synchronizer to fetch <strong>and<\/strong> transform the data from the ERP to this second database.<\/li><li>The data is not necessarily real-time with SAP, you have to wait for the synchronizer to fetch the latest updates.<\/li><\/ul><p>And I can honestly say that it\u2019s hugely compensated by the benefits it brings.<\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-97a3736 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"97a3736\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t\t\t<div class=\"elementor-row\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-d1faab6\" data-id=\"d1faab6\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-column-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-e1d2474 elementor-widget elementor-widget-heading\" data-id=\"e1d2474\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Global Architecture<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1ab5785 elementor-widget elementor-widget-text-editor\" data-id=\"1ab5785\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p>And\u2026 There we are with our final architecture. Let&rsquo;s recap:<\/p><ul><li style=\"list-style-type: none;\"><ul><li>A request is being sent to our custom API, written in ASP .NET Core<\/li><li>This request is being forwarded either<ul><li>To the service layer when data needs to be <strong>added\/updated<\/strong> in B1.<\/li><li>To an ORM (Entity Framework Core) for <strong>reading<\/strong> purpose.<\/li><\/ul><\/li><li>Additionally, a synchronizer program runs every <em>x<\/em> minutes to transform, filter, and store B1 data into a second database.<\/li><\/ul><\/li><\/ul>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c97e366 elementor-widget elementor-widget-image\" data-id=\"c97e366\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-image\">\n\t\t\t\t\t\t\t\t\t<figure class=\"wp-caption\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/finalarch.png\" data-elementor-open-lightbox=\"yes\" e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6NTQyLCJ1cmwiOiJodHRwczpcL1wvam9uYXRoYW5wYXBhLmNvbVwvYmxvZ1wvd3AtY29udGVudFwvdXBsb2Fkc1wvMjAyMFwvMDZcL2ZpbmFsYXJjaC5wbmcifQ%3D%3D\">\n\t\t\t\t\t\t\t<img width=\"812\" height=\"537\" src=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/finalarch-1024x677.png\" class=\"attachment-large size-large\" alt=\"\" loading=\"lazy\" srcset=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/finalarch-1024x677.png 1024w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/finalarch-300x198.png 300w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/finalarch-768x508.png 768w, https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/finalarch.png 1124w\" sizes=\"(max-width: 812px) 100vw, 812px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t<figcaption class=\"widget-image-caption wp-caption-text\">Application architecture<\/figcaption>\n\t\t\t\t\t\t\t\t\t\t<\/figure>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c0b5664 elementor-widget elementor-widget-text-editor\" data-id=\"c0b5664\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p>And guess what, it works like a charm!<\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-d3c8178 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"d3c8178\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t\t\t<div class=\"elementor-row\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c0e681a\" data-id=\"c0e681a\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-column-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-81a1512 elementor-widget elementor-widget-heading\" data-id=\"81a1512\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Conclusion<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c142ed0 elementor-widget elementor-widget-text-editor\" data-id=\"c142ed0\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p>This is the first time I am able to build (top to bottom) an enterprise-grade solution with an architecture that I had in mind since I started developing my small B1 web client (you can read about that in my previous articles, in this blog)<\/p><p>I can\u2019t stress how rewarding it feels to see it come to life and get used in order to make people\u2019s life easier in their daily tasks.<\/p><p>At the same time, I was also busy working on another project, but this time, with an existing <strong>MSSQL<\/strong> installation. If you\u2019re curious to see how I got it working without the Service Layer, stay tuned! \ud83d\ude0a<\/p><p>Thanks for reading and hope you liked the article! Cheers. \ud83e\udd19\u00a0<\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-9166542 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"9166542\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t\t\t<div class=\"elementor-row\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-444a51e\" data-id=\"444a51e\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-column-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-111e4f8 elementor-widget elementor-widget-menu-anchor\" data-id=\"111e4f8\" data-element_type=\"widget\" data-widget_type=\"menu-anchor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div id=\"gallery\" class=\"elementor-menu-anchor\"><\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f11bce4 elementor-widget elementor-widget-heading\" data-id=\"f11bce4\" data-element_type=\"widget\" id=\"gallery-anchor\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Gallery<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-58228d0 elementor-widget elementor-widget-text-editor\" data-id=\"58228d0\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\n\t\t\t\t<p>These are screens with data from a SAP B1 Demo database.<\/p>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b1c16fa elementor-arrows-position-inside elementor-pagination-position-outside elementor-widget elementor-widget-image-carousel\" data-id=\"b1c16fa\" data-element_type=\"widget\" data-settings=\"{&quot;slides_to_show&quot;:&quot;1&quot;,&quot;navigation&quot;:&quot;both&quot;,&quot;autoplay&quot;:&quot;yes&quot;,&quot;pause_on_hover&quot;:&quot;yes&quot;,&quot;pause_on_interaction&quot;:&quot;yes&quot;,&quot;autoplay_speed&quot;:5000,&quot;infinite&quot;:&quot;yes&quot;,&quot;effect&quot;:&quot;slide&quot;,&quot;speed&quot;:500}\" data-widget_type=\"image-carousel.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"elementor-image-carousel-wrapper swiper-container\" dir=\"ltr\">\n\t\t\t<div class=\"elementor-image-carousel swiper-wrapper\">\n\t\t\t\t\t\t\t\t<div class=\"swiper-slide\"><a data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-slideshow=\"b1c16fa\" data-elementor-lightbox-title=\"Home page\" e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6NTQ0LCJ1cmwiOiJodHRwczpcL1wvam9uYXRoYW5wYXBhLmNvbVwvYmxvZ1wvd3AtY29udGVudFwvdXBsb2Fkc1wvMjAyMFwvMDZcL1NfSG9tZS5wbmciLCJzbGlkZXNob3ciOiJiMWMxNmZhIn0%3D\" href=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/S_Home.png\"><figure class=\"swiper-slide-inner\"><img class=\"swiper-slide-image\" src=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/S_Home-1024x558.png\" alt=\"Home page\" \/><figcaption class=\"elementor-image-carousel-caption\">Home page<\/figcaption><\/figure><\/a><\/div><div class=\"swiper-slide\"><a data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-slideshow=\"b1c16fa\" data-elementor-lightbox-title=\"Purchase Order - Header\" e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6NTQ2LCJ1cmwiOiJodHRwczpcL1wvam9uYXRoYW5wYXBhLmNvbVwvYmxvZ1wvd3AtY29udGVudFwvdXBsb2Fkc1wvMjAyMFwvMDZcL1NfUE8xLnBuZyIsInNsaWRlc2hvdyI6ImIxYzE2ZmEifQ%3D%3D\" href=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/S_PO1.png\"><figure class=\"swiper-slide-inner\"><img class=\"swiper-slide-image\" src=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/S_PO1-1024x558.png\" alt=\"Purchase Order - Header\" \/><figcaption class=\"elementor-image-carousel-caption\">Purchase Order - Header<\/figcaption><\/figure><\/a><\/div><div class=\"swiper-slide\"><a data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-slideshow=\"b1c16fa\" data-elementor-lightbox-title=\"Purchase Order - Lines\" e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6NTQ3LCJ1cmwiOiJodHRwczpcL1wvam9uYXRoYW5wYXBhLmNvbVwvYmxvZ1wvd3AtY29udGVudFwvdXBsb2Fkc1wvMjAyMFwvMDZcL1NfUE8yLnBuZyIsInNsaWRlc2hvdyI6ImIxYzE2ZmEifQ%3D%3D\" href=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/S_PO2.png\"><figure class=\"swiper-slide-inner\"><img class=\"swiper-slide-image\" src=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/S_PO2-1024x558.png\" alt=\"Purchase Order - Lines\" \/><figcaption class=\"elementor-image-carousel-caption\">Purchase Order - Lines<\/figcaption><\/figure><\/a><\/div><div class=\"swiper-slide\"><a data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-slideshow=\"b1c16fa\" data-elementor-lightbox-title=\"Purchase Order - B1 Synchronization\" e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6NTQ1LCJ1cmwiOiJodHRwczpcL1wvam9uYXRoYW5wYXBhLmNvbVwvYmxvZ1wvd3AtY29udGVudFwvdXBsb2Fkc1wvMjAyMFwvMDZcL1NfUE9fQjFTeW5jLnBuZyIsInNsaWRlc2hvdyI6ImIxYzE2ZmEifQ%3D%3D\" href=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/S_PO_B1Sync.png\"><figure class=\"swiper-slide-inner\"><img class=\"swiper-slide-image\" src=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/S_PO_B1Sync-1024x558.png\" alt=\"Purchase Order - B1 Synchronization\" \/><figcaption class=\"elementor-image-carousel-caption\">Purchase Order - B1 Synchronization<\/figcaption><\/figure><\/a><\/div><div class=\"swiper-slide\"><a data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-slideshow=\"b1c16fa\" data-elementor-lightbox-title=\"Browsing suppliers\" e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6NTQ4LCJ1cmwiOiJodHRwczpcL1wvam9uYXRoYW5wYXBhLmNvbVwvYmxvZ1wvd3AtY29udGVudFwvdXBsb2Fkc1wvMjAyMFwvMDZcL1NfUE9TZWFyY2gucG5nIiwic2xpZGVzaG93IjoiYjFjMTZmYSJ9\" href=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/S_POSearch.png\"><figure class=\"swiper-slide-inner\"><img class=\"swiper-slide-image\" src=\"https:\/\/jonathanpapa.com\/blog\/wp-content\/uploads\/2020\/06\/S_POSearch-1024x558.png\" alt=\"Browsing suppliers\" \/><figcaption class=\"elementor-image-carousel-caption\">Browsing suppliers<\/figcaption><\/figure><\/a><\/div>\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"swiper-pagination\"><\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-swiper-button elementor-swiper-button-prev\">\n\t\t\t\t\t\t<i aria-hidden=\"true\" class=\"eicon-chevron-left\"><\/i>\t\t\t\t\t\t<span class=\"elementor-screen-only\">Pr\u00e9c\u00e9dent<\/span>\n\t\t\t\t\t<\/div>\n\t\t\t\t\t<div class=\"elementor-swiper-button elementor-swiper-button-next\">\n\t\t\t\t\t\t<i aria-hidden=\"true\" class=\"eicon-chevron-right\"><\/i>\t\t\t\t\t\t<span class=\"elementor-screen-only\">Suivant<\/span>\n\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Introduction A few months ago, I got involved in an SAP Business One project for an hotel in&nbsp;Luxembourg . Together, with a local SAP partner that took care of the functional analysis and provided me with the requirements, we were able to deliver a tailor-made solution for the customer. The aim was to build a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":561,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[10,12],"tags":[],"_links":{"self":[{"href":"https:\/\/jonathanpapa.com\/blog\/wp-json\/wp\/v2\/posts\/512"}],"collection":[{"href":"https:\/\/jonathanpapa.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jonathanpapa.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jonathanpapa.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jonathanpapa.com\/blog\/wp-json\/wp\/v2\/comments?post=512"}],"version-history":[{"count":11,"href":"https:\/\/jonathanpapa.com\/blog\/wp-json\/wp\/v2\/posts\/512\/revisions"}],"predecessor-version":[{"id":695,"href":"https:\/\/jonathanpapa.com\/blog\/wp-json\/wp\/v2\/posts\/512\/revisions\/695"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jonathanpapa.com\/blog\/wp-json\/wp\/v2\/media\/561"}],"wp:attachment":[{"href":"https:\/\/jonathanpapa.com\/blog\/wp-json\/wp\/v2\/media?parent=512"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jonathanpapa.com\/blog\/wp-json\/wp\/v2\/categories?post=512"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jonathanpapa.com\/blog\/wp-json\/wp\/v2\/tags?post=512"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}