📜 ⬆️ ⬇️

Portal in the service of accounting or automation of expense reports

Hello! Today we decided to share the results of a small but important project, as it is often very simple at first glance, things solve complex problems that give significant effectiveness in everyday life.

From our point of view, this material will be of interest primarily to those who are engaged in the development and development of internal portals, and thinks something useful can be done except for all the favorite reference books of employees, news, birthdays and the mother of their exchange rates.

So, let's imagine a medium-sized organization that is scattered across the territory of our large country, and it is these companies that choose SharePoint as a corporate portal. The most ordinary employee is going to go on a business trip and here the most interesting begins: fill out an application, agree with the manager, transfer it to the personnel service, get an advance on expenses, go on a business trip, fill out a report, hand it over to the accounting department.

To be honest, while they were writing, they themselves became confused as to what should be done in what sequence, and yet they still need to remember how to arrange everything correctly.
If you present it graphically, it looks like this:


')
Figures from real life - the staff of our customer makes 20,000 business trips per year, can you say there can be no such thing? is it not real? But let's look at this figure in a different way - these 20,000 missions are made by 4,000 people. That is, an average of 5 trips per person per year.

It is a real figure.

BUT if you count the time that is spent on supporting this process, then 200,000 hours are coming out ... Two hundred thousand hours, KARL!

At one point, management made this calculation, shed tears and decided that it was time to automate it all.

And how can this be automated?


We came up with a module on the customer’s corporate portal, integrated with the 1C and BOSS-HR personnel systems used in the company, which allows employees to carry out the entire process of coordinating trips and reporting on them electronically.

And the travel approval procedure began to look like this:



The deadline for applications and approval of reports was reduced to 1 day. You do not need the physical presence of specialists, you do not need to issue tons of paper documents. All online and in short order. And even from a mobile.

Sounds good, right? Now we will tell how we achieved it:

1) UI / UX-concept


The first step was to work through UI / UX — draw simple, consistent, logical, and convenient solution screens, and then move on to implementation.

This is how user screens look like:
List of travel and adding a new application


Travel request


The application approval by the head


Travel report form


And in this form, the expense report is seen by the manager and accounting department.


2) Snap to SharePoint


Then they started to fasten everything to the portal on SharePoint. The portal on the ball is all good, except that there is no transaction in it. But we are specialists to solve non-standard tasks.

We learned to bypass it like this:
1. For example, for storing the list of cities, targets, and dates, we added a Note field to the SharePoint list:
<Field Type="Note" DisplayName="Destinations" ID="{0aa6522b-ce74-4148-9b54-b9b7cd218098}" Name="Destinations" NumLines="6" RichText="FALSE" /> 


2. When saving an item, the serialized JSON was saved in this field:
 requestListItem[Constants.Lists.Requests.Destinations] = JsonHelper.JsonSerializer(destinations); 


3. To obtain data about cities, goals and dates when viewing, we deserialize back:
 Destinations = JsonHelper.JsonDeserialize<RequestDestination[]>((string)item[Constants.Lists.Requests.Destinations]) 

Sim-Salabim and damage from Sharepoint removed.

3) Integration with BOSS-personnel officer and 1C


With the systems BOSS-HR and “1C Accounting” were integrated via SQL databases using EntityFramework. But this task is more or less standard and depends on specific configurations. We are sure you already know what to do without us.

4) Mobile version of the module


And, finally, they made a mobile version for processing travel requests on the fly.

You understand that an average of 5 business trips per person per year means one travels once a year, and another 50. There is another nuance - in this particular company, many people do not have stationary computers and especially laptops. Here for those who, without a laptop from one business trip, flies directly to another, the mobile form is simply irreplaceable.


So, how we ensured mobility.

JavaScript decided to use a single, and switching between the mobile view and the main one was done using SharePoint tools:

1. Created a device channel:


2. Made the switch MasterPage depending on the channel.

3. On the aspx page, they made the display and connection of scripts and css depending on the channel:
 <asp:Content ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server"> <PublishingWebControls:DeviceChannelPanel ID="DefaultPanel" runat="server" IncludedChannels="Default"> <defaultMain:Header runat="server"></defaultMain:Header> </PublishingWebControls:DeviceChannelPanel> <PublishingWebControls:DeviceChannelPanel runat="server" IncludedChannels="Mobile"> <mobileMain:Header runat="server"></mobileMain:Header> </PublishingWebControls:DeviceChannelPanel> <meta name="CollaborationServer" content="SharePoint Team Web Site" /> </asp:Content> <asp:Content ID="Content8" ContentPlaceHolderID="PlaceHolderMain" runat="server"> <PublishingWebControls:DeviceChannelPanel ID="DeviceChannelPanel1" runat="server" IncludedChannels="Default"> <defaultMain:Page runat="server"></defaultMain:Page> </PublishingWebControls:DeviceChannelPanel> <PublishingWebControls:DeviceChannelPanel runat="server" IncludedChannels="Mobile"> <mobileMain:Page runat="server"></mobileMain:Page> </PublishingWebControls:DeviceChannelPanel> </asp:Content> 


For the mobile and main display, they made View, which are similar in structure but differ in markup. Below are examples of lists of applications.

1. Basic:
  <div class="list-block"> <div class="list-header"> <h2 class="text-uppercase color-blue inline-block"> </h2> <button type="button" class="new-trip-button" data-bind="click: editRequest.newRequest"> </button> <!-- ko if: $root.user().hasDebt --> <div class="alert alert-danger text-center"> <span class="glyphicon glyphicon-alert pull-left"></span> <span>       <span data-bind="text: $root.user().debt"></span> RUB.      ,    .</span> </div> <!-- /ko --> <!-- ko if: $root.user().debt < 0 --> <div class="alert alert-danger text-center cred"> <span class="glyphicon glyphicon-alert pull-left"></span> <span>        <span data-bind="text: -$root.user().debt"></span> RUB.</span> </div> <!-- /ko --> </div> <div class="list-body" data-bind="with: requests"> <table class="table"> <thead> <tr class="text-muted"> <th></th> <th></th> <th></th> <th></th> <th></th> <th></th> <th></th> <th class="text-right"></th> </tr> </thead> <tbody> <!-- ko foreach: items --> <tr data-bind="css: { 'travel-request': needAnswer }"> <td class="status-block"> <small class="status travel-request">  </small> <strong class="link-blue-lg" data-bind="text: period, click: viewTripRequest"></strong> </td> <td> <!-- ko if: questions --> <i class="travel-request-icon" data-bind="click: $parent.conversation"></i> <!-- /ko --> <!-- ko if: statusID == 14 --> <i class="glyphicon icon-print" data-bind="click: $parent.print"></i> <!-- /ko --> </td> <td> <!-- ko if: forManager --> <i class="for-manager-icon"></i> <!-- /ko --> </td> <td> <!-- ko if: advanceReportStatus --> <i class="pink-doc-icon" data-bind="click: viewAdvanceReport"></i> <!-- /ko --> </td> <td> <span data-bind="text: city"></span> </td> <td> <div data-bind="text: statusDescription"></div> </td> <td> <div data-bind="text: goal"></div> </td> <td class="text-right"> <!-- ko if: advance.length > 0 --> <strong class="color-red" data-bind="text: advance, css: { 'color-red': statusID != 15 }"></strong> <!-- /ko --> <!-- ko if: advance.length == 0 --> <span class="text-muted"> </span> <!-- /ko --> </td> </tr> <!-- /ko --> </tbody> </table> </div> </div> 


2. Mobile:
 <div class="list-block last" data-bind="with: requests"> <div class="list-header"> <h1 class="color-blue text-uppercase inline-block"> </h1> <button type="button" class="new-trip-button" data-bind="click: $parent.editRequest.newRequest"></button> <!-- ko if: $root.user().hasDebt --> <div class="alert alert-danger"> <span class="glyphicon glyphicon-alert"></span> <span>       <span data-bind="text: $root.user().debt"></span> RUB.      ,    .</span> </div> <!-- /ko --> <!-- ko if: $root.user().debt < 0 --> <div class="alert alert-danger cred"> <span class="glyphicon glyphicon-alert"></span> <span>        <span data-bind="text: -$root.user().debt"></span> RUB.</span> </div> <!-- /ko --> </div> <!-- ko foreach: items --> <div class="list-content"> <div class="row"> <div class="state-block"> <div class="form-group"> <small class="state bg-green color-white text-lowercase">  </small> </div> </div> </div> <div class="row"> <div class="col-xs-8"> <div class="form-group"> <span class="text-large" data-bind="text: statusDescription"></span> </div> </div> <div class="col-xs-4"> <div class="form-group text-right"> <!-- ko if: advance.length > 0 --> <span class="color-red text-large" data-bind="text: advance"></span> <!-- /ko --> <!-- ko if: advance.length == 0 --> <span class="text-muted text-large"> </span> <!-- /ko --> </div> </div> </div> <div class="row list-foot"> <div class="col-xs-4"> <h4><a href="javascript://" class="link link-blue" data-bind="text: period, click: viewTripRequest"></a></h4> </div> <div class="col-xs-4"> <h4 class="icon" data-bind="text: city, css: { 'icon-rus': tripType[0] == ' ', 'icon-non-rus': tripType[0] == '' }"></h4> </div> <div class="col-xs-4"> <!-- ko if: advanceReportStatus --> <span class="icon-attach" data-bind="click: viewAdvanceReport"></span> <!-- /ko --> <!-- ko if: questions --> <i class="travel-request-icon" data-bind="click: $parent.conversation"></i> <!-- /ko --> <!-- ko if: advanceReportStatus == '  ' --> <i class="icon-print" data-bind="click: $parent.print"></i> <!-- /ko --> </div> </div> </div> <!-- /ko --> </div> 


Voila!

This is how traditional processes that have worked for years can be changed and made quick and convenient, and most importantly, less costly in terms of resources.

At the same time, we did not reinvent the wheel, but gently integrated into the existing IT ecosystem of the customer. The company has long and long chosen a strategy for working with a corporate portal as the main tool for communication with employees. And we are happy to help them make the SharePoint portal a truly effective work resource.

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


All Articles