O kompaniji
Bee IT logo

Bee IT


About us

Our beginnings resemble a classic startup story. Our two founders, Zoran Tovarloža and Nikola Gorjanac, began their journey as colleagues forging their path in the IT industry together. At the beginning of 2017, they ventured off and founded Bee IT. Ever since, our company’s goal has been to deliver quality web, software development, and eCommerce services and solutions to customers. Today, Bee IT is a vibrant company that work with our forgein clients from Europe, USA and the Middle East using the latest generation tools and technologies.




 Transparent communication - Our cooperative environment is based on mutual
respect and open communication where we appreciate free expressions of
personal opinions.

Trust and dedication - Our clients count on our team, and our team counts on
its members. We have nurtured an environment based on honesty, trust and
accountability since day one.

We are a team - Each project is an opportunity to learn something new and hone
our craft, and with each new client - we get better at what we do.

Solidarity - Our colleagues are always there to help out. When there’s a
challenge to be solved, we are all there to help find a solution.

Tech stack

Salesforce Commerce Cloud Magento 2 PHP ReactJS React Native VueJS NodeJS HTML5 CSS3


Competitive salary

Latest technologies

New career opportunities as the company evolves in the future

Flexible working hours

Private health insurance

Paid English language classes

Paid education and courses

1 on 1 coaching sessions and internal soft skills training

Regular team-building events and fun activities

Paid sports activities

Working in a modern, pet friendly office

Our people

Zoran Tovarloža

CEO and Co-founder

Nikola Gorjanac

CTO and Co-founder

Sonja Tatarin Ragaji

HR Manager

Violeta Klisarić

HR Generalist

Our stories


Increasing your Revenue with Abandoned Cart Feature

Email marketing is a way to promote products or services through email. It is used as a top digital media channel, and it is important for customer acquisition and retention. In this blog, we will build a mechanism that will collect data from an abandoned cart along with a visitor's email address, store it into a custom object, so that after a certain time we can use that data to notify our customers through email that they have uncompleted orders. We will achieve this with Salesforce Commerce Cloud, using some built-in functionalities in business manager and writing a custom code to support it. STORING INFORMATION ABOUT ABANDONED CARTS As we don't have any system object to store the data for all incomplete orders, we need to create our own custom object type. Following the path Administration > Site Development > Custom Object Types, we can find all the custom object types that are already created. To create a new one, we need to click New and provide an ID, which needs to be unique. A Key Attribute is also a unique identifier for the object type. From the dropdown menu, select a Storage Scope that determines whether it is assigned to a specific site or the entire organization. In the image below, you can see what we used for our case. After that, we need to go to the Attribute Definitions tab and add fields that will store information about a specific order. That information is the customer's email address, the cart's total price, an indication if the customer is a registered user or a guest, and a JSON object containing the cart's data before the customer decided to abandon it. We will achieve that by clicking on New and then defining the attribute by choosing a unique ID, a preferred Display Name, and an appropriate Value Type, and clicking Apply. In our case, for the customer’s email, the Value Type will be a String type, for totalPrice a Number, registeredCustomer Boolean, and for the JSON object a Text type. You can check out one example in the image below. To make it work, we also need to group the attributes that we created by going to the Attribute Grouping tab and creating a new Attribute Group by choosing an ID that is unique for this type and an arbitrary name. In our case, the ID will be ‘default’ and the name is ‘Default’, and after that, we click Add. Now we need to assign our attributes to the newly created group. Clicking the Edit link, we will be redirected to the Assign Attribute Definition page where we need to click the three-dot button, and now we have a popup that contains all the attributes of this object type. In our case, we will choose our new attributes along with the type ID required to identify the object later in the code. Now, by clicking the Select button, we have assigned the attributes. In addition, we will add a new Site Preferences group so the feature can be configurable. Firstly, we need to go to Administration -> System Object Types and search for SitePreferences. In the Site Preferences, we need to add two Attribute Definitions. AbandonedCartEnabled is a Boolean that tells us if the feature is enabled or not, and abandonedCartEmail is the email address from where we will be sending the objects. After that, we need to go to Attribute Grouping, create a new group called Abandoned Cart and add all three attributes to it. Now, we will need to set the values for the attributes by going to Merchant Tools->Custom Preferences. Find Abandoned Cart and add the values you want to the two fields as shown in the image below. After all these steps are done successfully, we have our custom object type and site preferences created in the business manager, and now we need to do some coding to implement it on our site. After all these steps are done successfully, we have our custom object type and site preferences created in the business manager, and now we need to do some coding to implement it on our site. CREATING AND HANDLING CUSTOM OBJECTS Firstly, we will create a helper with functions for handling the objects that will be used later in the code. The createNewObject function is used to initially create the custom objects and store them in the database. Start with mapping fields of the product that are important for restoring the basket afterwards, followed by creating a unique ID, which is created by merging the basket UUID and Date.now() timestamp. Now, by calling createCustomObject from customObectjMgr and passing the name of the object as the first parameter and the ID as the second, it will create it and store it in the custom object. Now we need to fill the object fields, and to do that, we will wrap it in a Transaction so it can be saved to the DB. Besides that, we will need to store the basket UUID and the abandoned cart ID to the session that will be used to make sure that we already created an object for the session and prevent it from making another one each time we enter the checkout process. For deleteObject we will just need the ID of the custom object, and by calling the remove() function and passing that ID, it will delete the object. Also, we need to delete the previously stored data from the session. UpdateCartInfo will be used when adding, removing and updating lineItems on the basket level. For that one, we will again just need the ID of the custom object to get it with the getCustomObject function, and similar to createNewObject, we will map the product and update the object by wrapping it all into a transaction. Similar to updating the cart, we will create the updateEmail function that will be used if a guest user changes it at the beginning of the checkout process. For this example, the object will be created in two cases, one for guest customers as soon as we know their email addresses, and one for logged customers at the moment of creating the basket. To cover the guest customer scenario, we need to extend the CheckoutServices.js controller from the base cartridge by using the server.extend function with a module.superModule parameter and appending the 'SubmitCustomer' endpoint. After we check if the feature is enabled in Site Preferences, we will check if the custom object is already created by looking into the data from the session and update the email to make sure it is the latest one. Now, if the basket is available, we will use our custom function createNewObject to create our custom object. Now, as we covered guest users, we need to cover the second case, and that is the registered customer. As we know the customer’s email right away, we will create the object as soon as they add a product to the basket. To achieve that, we will need to extend the AddProduct, RemoveProductLineItem and UpdateQuantity endpoint. As the helpers are already created, the logic is pretty straightforward for all endpoints. So, basically again making sure that the feature is enabled in Site Preferences, that the customer logged in, and if we have the current basket already saved in the session, we can decide whether we should call createNewObject or updateCartInfo. We have just one specific case here and that is when removing a product from the cart, we need to check if the basket is empty, in which case we will call the deleteObject function to delete the whole custom object. The email is sent only if the customer has abandoned the cart, so we need to make sure to delete the object if the customer actually places the order. So, we will now append the PlaceOrder endpoint the same way as we did with the last one using another custom-made function. All custom objects that we created can be found by going to site > Custom Objects > Custom Object Editor, finding our object type name from the list, and hitting the find button. It should be noted that on this page, with the right permissions, we can edit, add and remove our object manually, but these functionalities should be used just for testing purposes while implementing the code. One thing we need to keep in mind is that we have limits set for the number of created object types to 300 and a total of 400,000 custom objects, with a warning at 240,000. Now that we have the procedure to save all the necessary data, we can create a job that runs once at a time, fetches the objects one by one, and sends an email with the cart content to every customer for which we have created an object 15 days before the job executed, and after the email is successfully sent, deletes the custom object to make sure we don't exceed the limit we mentioned above. It is also recommended to set a retention on the custom object itself so we prevent sending really old abandoned carts to customers. CREATING A JOB A good practice when making some integrations is to create a new cartridge and name it with a prefix int as I have done in this example. Now, the first thing that needs to be done is to configure a step type by creating a JSON file as shown below. (više)



Broj Zaposlenih


Profit i Prihod


Bulevar oslobođenja 83, Novi Sad, Serbia
+381 213001518