Some eLegere workflows may require to keep updated data between two applications.
Example
Business processes requiring data sync or updates between eLegere applications:
Adding a project's row in a project management application updates a monthly budget's row in a Budget application.
Updating the worked hours in the application calculating paychecks after completing an activity in a task management application.
Syncing information between two applications in two eLegere Domains.
This tutorial considers the following use case common to different circumstances: You have two applications and their SQL tables. Changes in the first application's table trigger changes in the second application's table.
Example
The tutorial considers the following application as the use case to show how to write a Stored Procedure.
Two applications manage purchases from an e-commerce site: Warehouse Orders and Warehouse Stock.
Warehouse Orders records the customers' orders and shipment from the warehouse.
Each Master row in Warehouse Orders is a shipment with a Detail table called "Order Items". "Order Items" lists all the requested products and their quantity.
Warehouse Stock catalogues the products and the stock available. If a product is out of stock, the application highlights its row and sends a notification to restock it.
When users add items to "Order Items" Detail table in Warehouse Orders , then they must update the items' availability in Warehouse Stock manually. (The same happens when users remove an item from an order.) The Designer should find a way to sync the two applications automatically to avoid waste of time.
Prepare the Action in the application's Design Mode to automate the execution.
Info
Each section in Configuring the Stored Procedures in the Database describes the Stored Procedure step by step through pseudocode. Code snippets of each part accompany the explanation. At the bottom of each section you can find the whole SQL Stored Procedure ready to be copied & pasted.
What You Should Know and What Permissions You Need?¶
Read the required list of skills, database permissions in your current eLegere installation, and database configurations .
If you satisfy the requirements below, you can undertake this tutorial.
The Stored Procedures require the F_APP_DATETIME2BIGINT function to work. Be sure to add it to the database if missing.
The Stored Procedures employ the function F_APP_DATETIME2BIGINT. F_APP_DATETIME2BIGINT converts a DateTime value into date expressed as a 14-digit number compatible with eLegere. During the eLegere installation, you DBA should have added it.
Add F_APP_DATETIME2BIGINT to the user-defined functions in case the database hasn't it.
-- Be sure to name the function F_APP_DATETIME2BIGINT.USE[SMARTINTELLIGENCE]GOSETANSI_NULLSONGOSETQUOTED_IDENTIFIERONGOCREATEFUNCTION[elegere].[F_APP_DATETIME2BIGINT](@dtDateTimedatetime)RETURNSBIGINTASBEGINDECLARE@biDateTimeASBIGINTSET@biDateTime=DATEPART(second,@dtDateTime)+DATEPART(minute,@dtDateTime)*100+DATEPART(hour,@dtDateTime)*10000+DATEPART(day,@dtDateTime)*1000000+DATEPART(month,@dtDateTime)*100000000+DATEPART(year,@dtDateTime)*10000000000RETURN(@biDateTime)ENDGO
Configuring the Stored Procedures in the Database¶
This section explains each Stored Procedure that you must configure in the database.
You must first configure the Stored Procedures in the eLegere's database before the eLegere application.
Note
When a user with Application Management permission (see What are the Design Tasks? for more information) creates an application, eLegere inserts the following empty Stored Procedures in the database:
SP_Application_Name_PRE_INSERT
SP_Application_Name_POST_INSERT
SP_Application_Name_PRE_UPDATE
SP_Application_Name_POST_UPDATE
SP_Application_Name_PRE_DELETE
SP_Application_Name_POST_DELETE
Insert the code according to the role in the corresponding Stored Procedure. For instance, paste PRE INSERT in SP_Warehouse_Management_Warehouse_Orders_PRE_INSERT.
The Stored Procedures' Flow in the Application subsection describes the Stored Procedures' workflow and when the application launch them and why.
The following subsections explain with comments each Stored Procedure to be configured in the database for each case.
This subsection describes the overall workflow in which each Stored Procedure edit data.
The flowchart below summarizes how each Stored Procedures work in the Warehouse Orders use case. Expand to view it.
Stored Procedures Flowchart
---
title: Stored Procedures Flowchart
---
flowchart TD
begin[[BEGIN]] --> choice1{Is the user adding products to Order Items?}
choice1-- Yes -->preinsert[The PRE INSERT Stored Procedure checks \nif there are enough product's units in stock]
preinsert --> choice2{Are there enough units in stock?}
choice2-- Yes --> newrow[The application creates the new row]
choice2-- No -->abort[The application blocks the row's creation.\nInforms the user about the reason]
abort-->ending[[END]]
newrow --> postinsert[The POST INSERT Stored Procedure updates \nthe units in stock after the application saves the new row]
postinsert --> ending
choice1-- No -->choice3{Is the user updating \na product's quantity in an order?}
choice3-- Yes --> preupdate[The PRE UPDATE Stored Procedure checks \nif there are enough product's units in stock]
preupdate --> choice4{Are there enough units in stock?}
choice4-- Yes --> updatedrow[The application updates the Quantity fields]
choice4-- No --> abort
updatedrow --> postupdate[The POST UPDATE Stored Procedure updates \nthe units in stock after the application saves the new row]
postupdate --> ending
choice3 -- No --> delete{The user deletes \na product from an order or an entire order}
delete --> predelete[The PRE DELETE updates the products' quantity]
predelete --> deletion[The application deletes the rows]
deletion-->ending
The key requirement is updating a product quantity in Warehouse Stock every time the user saves any change in Warehouse Orders-
A change in a product quantity can happen in four different moments:
When the user in Warehouse Orders adds a product to the Detail table Order Items.
When the user in Warehouse Orders removes a product to the Detail table Order Items.
When the user in Warehouse Orders changes a product's quantity in the Detail table Order Items.
When the user deletes a whole order's row from Warehouse Orders and its Detail table.
Each Stored Procedure covers one the cases 1-4 above.
The PRE INSERT and POST INSERT Stored Procedure update the quantities in case 1.
The PRE UPDATE and POST POST UPDATE Stored Procedure update the quantities in case 2.
The PRE DELETE updates the product quantities in case 3 and 4.
Why There Isn't a POST DELETE Stored Procedure?
A POST DELETE Stored Procedure is pointless for two reasons:
The PRE DELETE updates the product's quantity before the deletion.
The application would run a Stored Procedure on a non-existent row that the user has just deleted.
The Stored Procedure begins by creating the procedure and declaring all the mandatoryparameters that eLegere requires for SQL. (See Stored Procedures for more information about the parameters.)
Note
In eLegere you can retrieve the information about rows to be saved through the JSON object.
The JSON object must be passed to the Stored Procedure as value for the @jsonParameters.
The Item key in the JSON object contains the row's object with all the keys and values containing its information.
The StorageName key contains the eLegere Storage's SQL table Name. The name (i.e. [SQL TABLE NAME]) is the Storage's physical name in eLegere. Corresponds to the table where the user is performing the action.
UserId is the logon's Username.
Refer to the object "Item" within the JSON to obtain the new row's field values. Use the following command to open the new row's JSON object:
1
OPENJSON(@jsonParameters,'$.Item')
Refer the "Item" value through the JSON_VALUE() function. It's useful when you use SET or SELECT commands.
1
JSON_VALUE(@jsonParameters,'$.Item.FIELD_NAME')
Store Procedures can use the "StorageName" key value to run queries and actions according to the table. The current use case employs quite often the "StorageName" to verify conditions.
See Stored Procedures for more information about the SQL Parameters for eLegere.
After declaring the variables, set their values. The Store Procedures assigns a value for the tables' names since they're required in the following part. It uses the GETDATE() function to obtain the current DateTime and convert it in a Numeric format.
The procedure at step 4 assigns the converted date as Timestamp for the row.
The procedure opens the JSON Object that the procedure receives for the @jsonParameters and assigns the values to the variables.
Next, the procedure runs the first check: verifying that the application is saving in the Order Items table. If the table corresponds to Order Items's table TBL_ORDER_ITEMS, the procedure goes for the second check before allowing the saving process. Otherwise, nothing happens.
If the table name's from the JSON object is TBL_ORDER_ITEMS, the Store Procedures starts the second check. The second check verifies the product units in Warehouse Stock table TBL_PRODUCTS. Records the '$.Item.Quantity' key's value from the "Items" object to compare it with the WarehouseQuantity field. If '$.Item.Quantity' value is higher than the WarehouseQuantity's value for the product on TBL_PRODUCTS, the procedure blocks the saving process.
If the procedure blocks the new row's saving process, it reports a notification error to the user.
SET@ActionTargetStorage=ISNULL(JSON_VALUE(@jsonParameters,'$.StorageName'),@ApplicationMasterStorage)IF@ActionTargetStorage=@ApplicationDetailStorageBEGINSELECT@Id=JSON_VALUE(@jsonParameters,'$.Item.Id'),@QuantityOrder=JSON_VALUE(@jsonParameters,'$.Item.Quantity'),@ProductOrder=JSON_VALUE(@jsonParameters,'$.Item.Product'),@USERID_CREATION=JSON_VALUE(@jsonParameters,'$.Item.USER_ID_CREATION'),@USERID_LASTUPDATE=JSON_VALUE(@jsonParameters,'$.Item.USER_ID_LAST_UPDATE'),@DT_CREATION=JSON_VALUE(@jsonParameters,'$.Item.DT_CREATION'),@UPDATE_DATE=JSON_VALUE(@jsonParameters,'$.Item.DT_LAST_UPDATE'),@TIMESTAMP=CONVERT(VARBINARY(4),ISNULL(JSON_VALUE(@jsonParameters,'$.Item.TIMESTAMP'),'0x00000001'))FROMOPENJSON(@jsonParameters,'$.Item')SELECT@QuantityStock=WarehouseQuantityFROM[whrman].[TBL_PRODUCTS]WHEREIdProduct=@ProductOrderIF(@QuantityOrder>@QuantityStock)BEGINSET@OutCodeStatus='000500'SET@OutMessage='The requested quantity exceeds the current product stock.'SET@OutLevel='Error'RETURN-1ENDEND
-- Creates the procedure declaring the parameters that eLegere requiresCREATEPROCEDURE[whrman].[SP_Warehouse_Management_Warehouse_Orders_PRE_INSERT]@jsonParametersNVARCHAR(MAX),@OutCodeStatusNVARCHAR(4000)OUTPUT,@OutLevelNVARCHAR(4000)OUTPUT,@OutMessageNVARCHAR(4000)OUTPUTASBEGIN-- Variables declaration/* The variables will record info regarding the tables involved in the databases. */DECLARE@ApplicationNameNVARCHAR(4000)DECLARE@ApplicationMasterStorageNVARCHAR(4000)DECLARE@ApplicationDetailStorageNVARCHAR(4000)DECLARE@ActionTargetStorageNVARCHAR(4000)---------------- The following variables record the fields valuesDECLARE@IdINTDECLARE@ProductOrderINTDECLARE@QuantityOrderINTDECLARE@QuantityStockINTDECLARE@USERID_CREATIONNVARCHAR(4000)DECLARE@USERID_LASTUPDATENVARCHAR(4000)DECLARE@DT_CREATIONBIGINTDECLARE@UPDATE_DATEBIGINTDECLARE@TIMESTAMPVARBINARY(4)DECLARE@TodayASBIGINTDECLARE@dtTodayASDATETIME---------------- Sets the current system date as @dtToday valueSET@dtToday=GETDATE()/* Converts the DateTime value to integer format. Assigns the converted value to the @Today variable. */SET@Today=[dbo].F_APP_DATETIME2BIGINT(@dtToday)-- Assigns the table names on the database to the variablesSET@ApplicationName='Warehouse Orders'SET@ApplicationMasterStorage='TBL_WAREHOUSE_ORDERS'SET@ApplicationDetailStorage='TBL_ORDER_ITEMS'/* Assigns the value to the @ActionTargetStorage The assignment employs the row's context: checks the Storage's name from the JSON containing the data to save. - If the Storage Name is null, the user has saved a row in the Master table. It registers the @ApplicationMasterStorage value for @ActionTargetStorage. - If the Storage Name IS NOT null, the user has saved the row on the Detail. The procedure records the Detail table's name value from the JSON. */SET@ActionTargetStorage=ISNULL(JSON_VALUE(@jsonParameters,'$.StorageName'),@ApplicationMasterStorage)/* The procedure confronts @ActionTargetStorage and @ApplicationDetailStorage. If the table names are the same, the user has added a row to the Order Items Detail table. In this case, the procedure checks if the requested quantity is available in stock. Otherwise, the procedure is over. */IF@ActionTargetStorage=@ApplicationDetailStorageBEGIN/* The JSON contains the object Item. Item has all the row's fields and values. The procedure retrieves all the required values from Item. Retrives the Product information starting from the product's Id from the JSON. */SELECT@Id=JSON_VALUE(@jsonParameters,'$.Item.Id'),@QuantityOrder=JSON_VALUE(@jsonParameters,'$.Item.Quantity'),@ProductOrder=JSON_VALUE(@jsonParameters,'$.Item.Product'),@USERID_CREATION=JSON_VALUE(@jsonParameters,'$.Item.USER_ID_CREATION'),@USERID_LASTUPDATE=JSON_VALUE(@jsonParameters,'$.Item.USER_ID_LAST_UPDATE'),@DT_CREATION=JSON_VALUE(@jsonParameters,'$.Item.DT_CREATION'),@UPDATE_DATE=JSON_VALUE(@jsonParameters,'$.Item.DT_LAST_UPDATE'),@TIMESTAMP=CONVERT(VARBINARY(4),ISNULL(JSON_VALUE(@jsonParameters,'$.Item.TIMESTAMP'),'0x00000001'))FROMOPENJSON(@jsonParameters,'$.Item')-- Retrives the product's quantity value from the Warehouse Stock's tableSELECT@QuantityStock=WarehouseQuantityFROM[whrman].[TBL_PRODUCTS]WHEREIdProduct=@ProductOrder-- Compares the user's inserted quantity and the product's quantity from Warehouse Stock.IF(@QuantityOrder>@QuantityStock)BEGIN--- In case the quantity is too low, the procedure blocks the save and warns the user with a notification.SET@OutCodeStatus='000500'SET@OutMessage='The requested quantity exceeds the current product stock.'SET@OutLevel='Error'RETURN-1ENDENDENDGO
At this step, the procedure updates the product's stock after the row is saved in Warehouse Orders. At this stage, the PRE INSERT Stored Procedure has already verified that there is enough stock and didn't block the saving process.
The query retrieves the selected product's row on the Warehouse Stock table TBL_PRODUCTS.
Then the procedure updates the entry on the table for WarehouseQuantity field.
Each product in Warehouse Stock has a Boolean field called isAvailable. If the product's quantity goes to 0, the procedure changes the isAvailableBoolean field from true to false. If isAvailable is false, the users in Warehouse Orders can't choose that product for an order.
-- Creates the procedure declaring the parameters that eLegere requiresCREATEPROCEDURE[whrman].[SP_Warehouse_Management_Warehouse_Orders_POST_INSERT]@jsonParametersNVARCHAR(MAX),@OutCodeStatusNVARCHAR(4000)OUTPUT,@OutLevelNVARCHAR(4000)OUTPUT,@OutMessageNVARCHAR(4000)OUTPUTASBEGIN-- Variables declaration/* The variables will record info regarding the tables involved in the databases. */DECLARE@ApplicationNameNVARCHAR(4000)DECLARE@ApplicationMasterStorageNVARCHAR(4000)DECLARE@ApplicationDetailStorageNVARCHAR(4000)DECLARE@ApplicationDetailStorage2NVARCHAR(4000)DECLARE@ActionTargetStorageNVARCHAR(4000)--------------/* The following variables record the updated rows' fields' values. @Today and @dtToday record the date in Numeric format and DateTime values. The Stored Procedure requires @Today and @dtToday to update the DT_CREATION field. */DECLARE@IdINTDECLARE@ProductOrderINTDECLARE@QuantityOrderINTDECLARE@USERID_CREATIONNVARCHAR(4000)DECLARE@USERID_LASTUPDATENVARCHAR(4000)DECLARE@DT_CREATIONBIGINTDECLARE@UPDATE_DATEBIGINTDECLARE@TIMESTAMPVARBINARY(4)DECLARE@TodayASBIGINTDECLARE@dtTodayASDATETIME-------------- -- Sets the current system date as @dtToday valueSET@dtToday=GETDATE()/* Converts the DateTime value to integer format. Assigns the converted value to the @Today variable. */SET@Today=[dbo].F_APP_DATETIME2BIGINT(@dtToday)-- Assigns the table names on the database to the variables.SET@ApplicationName='Warehouse Orders'SET@ApplicationMasterStorage='TBL_WAREHOUSE_ORDERS'SET@ApplicationDetailStorage='TBL_ORDER_ITEMS'/* Assigns the value to the @ActionTargetStorage. The assignment employs the row's context: checks the Storage's name from the JSON containing the data to save. - If the Storage's name is null, the user has saved a row in the Master table. It registers the @ApplicationMasterStorage value for @ActionTargetStorage. - If the Storage's nameame IS NOT null, the user has saved the row on the Detail. The procedure records the Detail table's name value from the JSON. */SET@ActionTargetStorage=ISNULL(JSON_VALUE(@jsonParameters,'$.StorageName'),@ApplicationMasterStorage)/* The procedures confronts @ActionTargetStorage and @ApplicationDetailStorage If the table names are the same, the user has added a row to the Order Items Detail table. In such case, the procedure updates Warehouse Stock. Otherwise, the procedure is over. */IF@ActionTargetStorage=@ApplicationDetailStorageBEGIN/* Retrives the Product information starting from the product's Id from the JSON. The JSON contains the object Item. Item has all the row's fields and values. The procedure retrieves all the required values from Item. */SELECT@Id=JSON_VALUE(@jsonParameters,'$.Item.Id'),@QuantityOrder=JSON_VALUE(@jsonParameters,'$.Item.Quantity'),@ProductOrder=JSON_VALUE(@jsonParameters,'$.Item.Product'),@USERID_CREATION=JSON_VALUE(@jsonParameters,'$.Item.USER_ID_CREATION'),@USERID_LASTUPDATE=JSON_VALUE(@jsonParameters,'$.Item.USER_ID_LAST_UPDATE'),@DT_CREATION=JSON_VALUE(@jsonParameters,'$.Item.DT_CREATION'),@UPDATE_DATE=JSON_VALUE(@jsonParameters,'$.Item.DT_LAST_UPDATE'),@TIMESTAMP=CONVERT(VARBINARY(4),ISNULL(JSON_VALUE(@jsonParameters,'$.Item.TIMESTAMP'),'0x00000001'))FROMOPENJSON(@jsonParameters,'$.Item')/* The query updates the Warehouse Stock table with the new quantity, date of update, and who has updated the quantity. PROD is the alias assigned to Warehouse Stock's table (TBL_PRODUCTS). Also, updates DT_LAST_UPDATE and USER_ID_LAST_UPDATE fields. DT_LAST_UPDATE records the latest update's date. USER_ID_LAST_UPDATE records the latest account that edited the row. */UPDATEPRODSETPROD.WarehouseQuantity=PROD.WarehouseQuantity-@QuantityOrder,PROD.DT_LAST_UPDATE=@UPDATE_DATE,PROD.USER_ID_LAST_UPDATE=@USERID_LASTUPDATEFROM[whrman].[TBL_PRODUCTS]ASPRODWHEREPROD.IdProduct=@ProductOrder/* Each product in TBL_PRODUCTS has a Boolean field called IsAvailable. If isAvailable is false, the users in Warehouse Orders can't choose the product for an order. When a product has the value 0 for the WarehouseQuantity field, the procedure changes the isAvailable's value. Also, updates DT_LAST_UPDATE and USER_ID_LAST_UPDATE fields. */UPDATE[whrman].[TBL_PRODUCTS]SETIsAvailable=0,DT_LAST_UPDATE=@UPDATE_DATE,USER_ID_LAST_UPDATE=@USERID_LASTUPDATEWHEREIdProduct=@ProductOrderANDWarehouseQuantity=0ENDENDGO
The Stored Procedure Before Saving the Changes to a Row¶
Follows the explanation of the Stored Procedure that the application will run before saving any change to existing rows in Order Items Detail table.
The procedure opens the JSON Object that the procedure receives for the @jsonParameters and assigns the values to the variables.
Then proceed with the first check: verifying that the table in which the application is saving is the Order Items table. If the table corresponds to Order Items's table TBL_ORDER_ITEMS, the Procedure proceeds with the second check before allowing the saving process. Otherwise, nothing happens.
If the table name's from the JSON object is TBL_ORDER_ITEMS, the Store Procedures starts the second check. The second check verifies the product units in Warehouse Stock table TBL_PRODUCTS.
The process for the second check changes from the PRE INSERT.
In the PRE UPDATE, the procedure executes a JOIN between TBL_ORDER_ITEMS and TBL_PRODUCTS to select the entries in common. The product's Id is the filter for the query.
The procedures subtracts the older product's quantity from the requested new quantity to calculate the change in quantity.
If the difference between actual product's stock and the change in quantity is lower than 0, there aren't enough product's units in stock. In this case, the procedure blocks the saving process and warns the user with a notification explaining the reason.
If the difference between actual product's stock and the change in quantity is more than 0, there are enough product's units in stock. In this case, the procedure updates the product's entry in Warehouse Stock. Then the application can save the updated row in Order Items Detail table.
SET@ActionTargetStorage=ISNULL(JSON_VALUE(@jsonParameters,'$.StorageName'),@ApplicationMasterStorage)IF@ActionTargetStorage=@ApplicationDetailStorageBEGINSELECT@Id=JSON_VALUE(@jsonParameters,'$.Item.Id'),@QuantityOrder_New=JSON_VALUE(@jsonParameters,'$.Item.Quantity'),@USERID_CREATION=JSON_VALUE(@jsonParameters,'$.Item.USER_ID_CREATION'),@USERID_LASTUPDATE=JSON_VALUE(@jsonParameters,'$.Item.USER_ID_LAST_UPDATE'),@DT_CREATION=JSON_VALUE(@jsonParameters,'$.Item.DT_CREATION'),@UPDATE_DATE=JSON_VALUE(@jsonParameters,'$.Item.DT_LAST_UPDATE'),@TIMESTAMP=CONVERT(VARBINARY(4),ISNULL(JSON_VALUE(@jsonParameters,'$.Item.TIMESTAMP'),'0x00000001'))FROMOPENJSON(@jsonParameters,'$.Item')SELECT@QuantityStock=PROD.WarehouseQuantity,@QuantityOrder_Old=ORD.Quantity,@ProductOrder=ORD.ProductFROM[whrman].[TBL_ORDER_ITEMS]ASORDINNERJOIN[whrman].[TBL_PRODUCTS]ASPRODONORD.Product=PROD.IdProductWHEREORD.Id=@IdSELECT@DeltaQuantity=@QuantityOrder_New-@QuantityOrder_OldIF(@QuantityStock-@DeltaQuantity<0)BEGINSET@OutCodeStatus='000500'SET@OutMessage='The requested quantity exceeds the current product stock.'SET@OutLevel='Error'RETURN-1ENDELSEBEGINUPDATEPRODSETWarehouseQuantity=WarehouseQuantity-@DeltaQuantity,DT_LAST_UPDATE=@UPDATE_DATE,USER_ID_LAST_UPDATE=@USERID_LASTUPDATEFROM[whrman].[TBL_PRODUCTS]ASPRODWHEREPROD.IdProduct=@ProductOrderEND
-- Creates the procedure declaring the parameters that eLegere requires.CREATEPROCEDURE[whrman].[SP_Warehouse_Management_Warehouse_Orders_PRE_UPDATE]@jsonParametersNVARCHAR(MAX),@OutCodeStatusNVARCHAR(4000)OUTPUT,@OutLevelNVARCHAR(4000)OUTPUT,@OutMessageNVARCHAR(4000)OUTPUTASBEGIN-- Variables declaration/* The variables will record info regarding the tables involved in the databases. */DECLARE@ApplicationNameNVARCHAR(4000)DECLARE@ApplicationMasterStorageNVARCHAR(4000)DECLARE@ApplicationDetailStorageNVARCHAR(4000)DECLARE@ActionTargetStorageNVARCHAR(4000)--------------/* The following variables record the updated rows' fields' values. @Today and @dtToday record the date in Numeric format and DateTime values. The Stored Procedure requires @Today and @dtToday to update the DT_CREATION field. */DECLARE@IdINTDECLARE@ProductOrderINTDECLARE@QuantityOrder_NewINTDECLARE@QuantityOrder_OldINTDECLARE@QuantityStockINTDECLARE@DeltaQuantityINTDECLARE@USERID_CREATIONNVARCHAR(4000)DECLARE@USERID_LASTUPDATENVARCHAR(4000)DECLARE@DT_CREATIONBIGINTDECLARE@UPDATE_DATEBIGINTDECLARE@TIMESTAMPVARBINARY(4)DECLARE@TodayASBIGINTDECLARE@dtTodayASDATETIME---------------- Sets the current system date as @dtToday valueSET@dtToday=GETDATE()/* Converts the DateTime value to integer format. Assigns the converted value to the @Today variable. */SET@Today=[dbo].F_APP_DATETIME2BIGINT(@dtToday)-- Assigns the table names on the database to the variablesSET@ApplicationName='Warehouse Orders'SET@ApplicationMasterStorage='TBL_WAREHOUSE_ORDERS'SET@ApplicationDetailStorage='TBL_ORDER_ITEMS'/* Assigns the value to the @ActionTargetStorage. The assignment employs the row's context: checks the Storage's name from the JSON containing the data to save. - If the Storage's name is null, the user has saved a row in the Master table. It registers the @ApplicationMasterStorage value for @ActionTargetStorage. - If the Storage's nameame IS NOT null, the user has saved the row on the Detail. The procedure records the Detail table's name value from the JSON. */SET@ActionTargetStorage=ISNULL(JSON_VALUE(@jsonParameters,'$.StorageName'),@ApplicationMasterStorage)/* The procedures confronts @ActionTargetStorage and @ApplicationDetailStorage If the table names are the same, the user has added a row to the Order Items Detail table. In such case, the procedure updates Warehouse Stock. Otherwise, the procedure is over. */IF@ActionTargetStorage=@ApplicationDetailStorageBEGIN/* The JSON contains the object Item. Item has all the row's fields and values. The procedure retrieves all the required values from Item. Retrives the Product information starting from the product's Id from the JSON. @QuantityOrder_New is the variable recording the new desired value. */SELECT@Id=JSON_VALUE(@jsonParameters,'$.Item.Id'),@QuantityOrder_New=JSON_VALUE(@jsonParameters,'$.Item.Quantity'),@USERID_CREATION=JSON_VALUE(@jsonParameters,'$.Item.USER_ID_CREATION'),@USERID_LASTUPDATE=JSON_VALUE(@jsonParameters,'$.Item.USER_ID_LAST_UPDATE'),@DT_CREATION=JSON_VALUE(@jsonParameters,'$.Item.DT_CREATION'),@UPDATE_DATE=JSON_VALUE(@jsonParameters,'$.Item.DT_LAST_UPDATE'),@TIMESTAMP=CONVERT(VARBINARY(4),ISNULL(JSON_VALUE(@jsonParameters,'$.Item.TIMESTAMP'),'0x00000001'))FROMOPENJSON(@jsonParameters,'$.Item')/* Assigns the values needed for the query to the varibles. ORD is the alias for the Warehouse Order's table. PROD is the alias for Warehouse Stock's table. Then the query flters both the tables for the product entries that have the same product's Id. */SELECT@QuantityStock=PROD.WarehouseQuantity,@QuantityOrder_Old=ORD.Quantity,@ProductOrder=ORD.ProductFROM[whrman].[TBL_ORDER_ITEMS]ASORDINNERJOIN[whrman].[TBL_PRODUCTS]ASPRODONORD.Product=PROD.IdProductWHEREORD.Id=@Id-- Calculates the difference between desired quantity and the previous order's quantity.SELECT@DeltaQuantity=@QuantityOrder_New-@QuantityOrder_Old/* Checks the stock's quantity in Warehouse Order by subtracting the difference. If the difference between stock and quantity is lower tha 0, the Stored Procedure blocks the action and yields an error notification. */IF(@QuantityStock-@DeltaQuantity<0)BEGINSET@OutCodeStatus='000500'SET@OutMessage='The requested quantity exceeds the current product stock.'SET@OutLevel='Error'RETURN-1ENDELSEBEGIN-- If there's enough stock, the procedures updates the quantity in Warehouse Stock.UPDATEPRODSETWarehouseQuantity=WarehouseQuantity-@DeltaQuantity,DT_LAST_UPDATE=@UPDATE_DATE,USER_ID_LAST_UPDATE=@USERID_LASTUPDATEFROM[whrman].[TBL_PRODUCTS]ASPRODWHEREPROD.IdProduct=@ProductOrderENDENDENDGO
The Stored Procedure After Saving the Changes to a Row¶
Follows the explanation of the Stored Procedure that the application will run after saving any change to existing rows in the Order Items Detail table.
At this step, the procedure updates the product's stock after the row is saved in Warehouse Orders. La PRE UPDATE Stored Procedure has already verified that there is enough stock and didn't block the saving process.
The query retrieves the selected product's row on the Warehouse Stock table TBL_PRODUCTS.
Then the procedure updates the entry on the table for WarehouseQuantity field.
Each product in Warehouse Stock has a field called isAvailable. If the product's quantity goes to 0, the procedure changes the isAvailableBoolean field from true to false. If isAvailable is false, the users in Warehouse Orders can't choose that product for an order. Otherwise, if the quantity returns above 0, the procedure sets the isAvailable field's value as true.
-- Creates the procedure declaring the parameters that eLegere requiresCREATEPROCEDURE[whrman].[SP_Warehouse_Management_Warehouse_Orders_POST_UPDATE]@jsonParametersNVARCHAR(MAX),@OutCodeStatusNVARCHAR(4000)OUTPUT,@OutLevelNVARCHAR(4000)OUTPUT,@OutMessageNVARCHAR(4000)OUTPUTASBEGIN-- Variables declaration/* The variables will record info regarding the tables involved in the databases. */DECLARE@ApplicationNameNVARCHAR(4000)DECLARE@ApplicationMasterStorageNVARCHAR(4000)DECLARE@ApplicationDetailStorageNVARCHAR(4000)DECLARE@ActionTargetStorageNVARCHAR(4000)--------------/* The following variables record the updated rows' fields' values. @Today and @dtToday record the date in Numeric Format and the DateTime values. The Stored Procedure requires @Today and @dtToday to update the DT_CREATION field. */DECLARE@IdINTDECLARE@USERID_CREATIONNVARCHAR(4000)DECLARE@USERID_LASTUPDATENVARCHAR(4000)DECLARE@DT_CREATIONBIGINTDECLARE@UPDATE_DATEBIGINTDECLARE@TIMESTAMPVARBINARY(4)DECLARE@TodayASBIGINTDECLARE@dtTodayASDATETIME---------------- Sets the current system date as @dtToday valueSET@dtToday=GETDATE()/* Converts the DateTime value to integer format. Assigns the converted value to the @Today variable. */SET@Today=[dbo].F_APP_DATETIME2BIGINT(@dtToday)-- Assigns the table names on the database to the variablesSET@ApplicationName='Warehouse Orders'SET@ApplicationMasterStorage='TBL_WAREHOUSE_ORDERS'SET@ApplicationDetailStorage='TBL_ORDER_ITEMS'/* Assigns the value to the @ActionTargetStorage. The assignment employs the row's context: checks the Storage's name from the JSON containing the data to save. - If the Storage's name is null, the user has saved a row in the Master table. It registers the @ApplicationMasterStorage value for @ActionTargetStorage. - If the Storage's nameame IS NOT null, the user has saved the row on the Detail. The procedure records the Detail table's name value from the JSON. */SET@ActionTargetStorage=ISNULL(JSON_VALUE(@jsonParameters,'$.StorageName'),@ApplicationMasterStorage)/* The procedures confronts @ActionTargetStorage and @ApplicationDetailStorage If the table names are the same, the user has added a row to the Order Items Detail table In this case, the procedure checks if the requested quantity is available in stock. Otherwise, the procedure is over. */IF@ActionTargetStorage=@ApplicationDetailStorageBEGIN/* Retrives the Product information starting from the product's Id from the JSON. The JSON contains the object Item. Item has all the row's fields and values. The procedure retrieves all the required values from Item. */SELECT@Id=JSON_VALUE(@jsonParameters,'$.Item.Id'),@USERID_CREATION=JSON_VALUE(@jsonParameters,'$.Item.USER_ID_CREATION'),@USERID_LASTUPDATE=JSON_VALUE(@jsonParameters,'$.Item.USER_ID_LAST_UPDATE'),@DT_CREATION=JSON_VALUE(@jsonParameters,'$.Item.DT_CREATION'),@UPDATE_DATE=JSON_VALUE(@jsonParameters,'$.Item.DT_LAST_UPDATE'),@TIMESTAMP=CONVERT(VARBINARY(4),ISNULL(JSON_VALUE(@jsonParameters,'$.Item.TIMESTAMP'),'0x00000001'))FROMOPENJSON(@jsonParameters,'$.Item')/* Each product in TBL_PRODUCTS has a Boolean field called isAvailable. If isAvailable is false, the users in Warehouse Orders can't choose the product for an order. When a product has the value equal or higher than 0 for the WarehouseQuantity field, the procedure changes the isAvailable's value. False if equal 0 or True when the quantity is more than 0. Also, updates DT_LAST_UPDATE and USER_ID_LAST_UPDATE fields. */UPDATEPRODSETIsAvailable=CASEWHENWarehouseQuantity=0THEN0ELSE1END,DT_LAST_UPDATE=@UPDATE_DATE,USER_ID_LAST_UPDATE=@USERID_LASTUPDATEFROM[whrman].[TBL_PRODUCTS]ASPRODINNERJOIN[whrman].[TBL_ORDER_ITEMS]ASORDONPROD.IdProduct=ORD.ProductWHEREORD.Id=@IdENDENDGO
At this step, the procedure updates the product's stock before the application has saved the rows' deletion in Warehouse Orders.
The Stored Procedure behaves differently according to Master and Detail table. The first check is verifying through the Storage's name if the edited table is the Master table.
If the table is the Master table, the procedure removes all the Detail table's rows (Order Items) and updates the quantities in Warehouse Stock.
If the Storage's name doesn't correspond to the Master table's name (TBL_WAREHOUSE_ORDERS), then the second check verifies if the user has deleted a row in Order Items' table.
Question
Why making a second check if there are only one Master and one Detail table? If table isn't the Master, then it must be TBL_PRODUCTS of the Detail.
The second check is necessary in case the Designer decides to add further Detail tables to Warehouse Orders.
In this way, the application will execute the procedure only on either the Master or the Order Items Detail table. So, if the user saves in a further Detail table, no action on Warehouse Stock's table will happen.
If the user deletes a product from an order, the procedures updates the quantity in stock in Warehouse Stock. Adds back to the order's quantity to the WarehouseQuantity's value.
If the WarehouseQuantity was 0, the procedure sets the isAvailable field's value back true. The product is back in stock and available.
-- Creates the procedure declaring the parameters that eLegere requiresCREATEPROCEDURE[whrman].[SP_Warehouse_Management_Warehouse_Orders_PRE_DELETE]@jsonParametersNVARCHAR(MAX),@OutCodeStatusNVARCHAR(4000)OUTPUT,@OutLevelNVARCHAR(4000)OUTPUT,@OutMessageNVARCHAR(4000)OUTPUTASBEGIN-- Variables declaration/* The variables will record info regarding the tables involved in the databases. */DECLARE@ApplicationNameNVARCHAR(4000)DECLARE@ApplicationMasterStorageNVARCHAR(4000)DECLARE@ApplicationDetailStorageNVARCHAR(4000)DECLARE@ActionTargetStorageNVARCHAR(4000)--------------/* The following variables record the updated rows' fields' values. @Today and @dtToday record the date in numeric format and DateTime values. The Stored Procedure requires @Today and @dtToday to update the DT_CREATION field. */DECLARE@IdINTDECLARE@IdOrderINTDECLARE@USERID_CREATIONNVARCHAR(4000)DECLARE@USERID_LASTUPDATENVARCHAR(4000)DECLARE@DT_CREATIONBIGINTDECLARE@UPDATE_DATEBIGINTDECLARE@TIMESTAMPVARBINARY(4)DECLARE@TodayASBIGINTDECLARE@dtTodayASDATETIME---------------- Sets the current system date as @dtToday valueSET@dtToday=GETDATE()/* Converts the DateTime value to integer format. Assigns the converted value to the @Today variable. */SET@Today=[dbo].F_APP_DATETIME2BIGINT(@dtToday)-- Assigns the table names on the database to the variablesSET@ApplicationName='Warehouse Orders'SET@ApplicationMasterStorage='TBL_WAREHOUSE_ORDERS'SET@ApplicationDetailStorage='TBL_ORDER_ITEMS'/* Assigns the value to the @ActionTargetStorage. The assignment employs the row's context: checks the Storage's name from the JSON containing the data to save. - If the Storage's name is null, the user has saved a row in the Master table. It registers the @ApplicationMasterStorage value for @ActionTargetStorage. - If the Storage's nameame IS NOT null, the user has saved the row on the Detail. The procedure records the Detail table's name value from the JSON. */SET@ActionTargetStorage=ISNULL(JSON_VALUE(@jsonParameters,'$.StorageName'),@ApplicationMasterStorage)-- There are two IF conditions to verify what table the deletion involves./* The procedure confronts @ActionTargetStorage and @ApplicationMasterStorage If the table names are the same, the user has deleted the whole order. So, the procedure will clear the Detail rows and update the stock before saving the row. */IF@ActionTargetStorage=@ApplicationMasterStorageBEGIN/* Retrives the product information starting from the product's Id from the JSON. The JSON contains the object Item. Item has all the row's fields and values. The procedure retrieves all the required values from Item. For the deletion, the procedure requires ony the Id and the fields recording information like the Timestamp, date of creation, date of update, and so on. */SELECT@Id=JSON_VALUE(@jsonParameters,'$.Item.Id'),@USERID_CREATION=JSON_VALUE(@jsonParameters,'$.Item.USER_ID_CREATION'),@USERID_LASTUPDATE=JSON_VALUE(@jsonParameters,'$.Item.USER_ID_LAST_UPDATE'),@DT_CREATION=JSON_VALUE(@jsonParameters,'$.Item.DT_CREATION'),@UPDATE_DATE=JSON_VALUE(@jsonParameters,'$.Item.DT_LAST_UPDATE'),@TIMESTAMP=CONVERT(VARBINARY(4),ISNULL(JSON_VALUE(@jsonParameters,'$.Item.TIMESTAMP'),'0x00000001'))FROMOPENJSON(@jsonParameters,'$.Item')/* The procedure stores the order's Id and searches it on TBL_WAREHOUSE_ORDERS for the key bounding the Detail to the Master rows. */SELECT@IdOrder=IdWarehouseOrderFROM[whrman].[TBL_WAREHOUSE_ORDERS]WHEREId=@Id/* Finds the products involved in the order through the products' IDs. Assigns to WarehouseQuantity the new value. Updates the products' quantity in stock. */UPDATEPRODSETWarehouseQuantity=PROD.WarehouseQuantity+ORD.QuantityFROM[whrman].[TBL_PRODUCTS]ASPRODINNERJOIN[whrman].[TBL_ORDER_ITEMS]ASORDONPROD.IdProduct=ORD.ProductWHEREWarehouseOrderId=@IdOrder/* Each product in TBL_PRODUCTS has a Boolean field called isAvailable. If isAvailable is false, the users in Warehouse Orders can't choose the product for an order. When a product has the value 0 for the WarehouseQuantity field, the procedure changes the isAvailable's value. When the updated product's quantity rises again from 0, the procedure changes the isAvailable's value to true. */UPDATEPRODSETIsAvailable=CASEWHENWarehouseQuantity>0THEN1ELSE0ENDFROM[whrman].[TBL_PRODUCTS]ASPRODINNERJOIN[whrman].[TBL_ORDER_ITEMS]ASORDONPROD.IdProduct=ORD.ProductWHEREWarehouseOrderId=@IdOrder-- Deletes all the Detail rows that have the same order's IdDELETEFROM[whrman].[TBL_ORDER_ITEMS]WHEREWarehouseOrderId=@IdOrderENDIF@ActionTargetStorage=@ApplicationDetailStorageBEGIN/* Retrives the product information starting from the product's Id from the JSON. The JSON contains the object Item. Item has all the row's fields and values. The procedure retrieves all the required values from Item. For the deletion, the procedures requires ony the Id and the fields recording information like the Timestamp, date of creation, date of update, and so on. */SELECT@Id=JSON_VALUE(@jsonParameters,'$.Item.Id'),@USERID_CREATION=JSON_VALUE(@jsonParameters,'$.Item.USER_ID_CREATION'),@USERID_LASTUPDATE=JSON_VALUE(@jsonParameters,'$.Item.USER_ID_LAST_UPDATE'),@DT_CREATION=JSON_VALUE(@jsonParameters,'$.Item.DT_CREATION'),@UPDATE_DATE=JSON_VALUE(@jsonParameters,'$.Item.DT_LAST_UPDATE'),@TIMESTAMP=CONVERT(VARBINARY(4),ISNULL(JSON_VALUE(@jsonParameters,'$.Item.TIMESTAMP'),'0x00000001'))FROMOPENJSON(@jsonParameters,'$.Item')/* Finds the products involved in the order through the products' IDs. Assigns to WarehouseQuantity the new value. Updates the product's quantity in stock. */UPDATEPRODSETWarehouseQuantity=PROD.WarehouseQuantity+ORD.QuantityFROM[whrman].[TBL_PRODUCTS]ASPRODINNERJOIN[whrman].[TBL_ORDER_ITEMS]ASORDONPROD.IdProduct=ORD.ProductWHEREORD.Id=@Id/* Each product in TBL_PRODUCTS has a Boolean field called isAvailable. If isAvailable is false, the users in Warehouse Orders can't choose the product for an order. When a product has the value 0 for the WarehouseQuantity field, the procedure changes the isAvailable's value. When the updated product's quantity rises again from 0, the procedure changes the isAvailable's value to true. */UPDATEPRODSETIsAvailable=1FROM[whrman].[TBL_PRODUCTS]ASPRODINNERJOIN[whrman].[TBL_ORDER_ITEMS]ASORDONPROD.IdProduct=ORD.ProductWHEREWarehouseQuantity>0ENDENDGO
This part requires the Application Designer permission from your administrator. (See What are the Design Tasks? for more information about Design permissions.)
After having saved the Stored Procedure in the database, you must enable it with all the related triggers in the Design Mode.
Follow the steps below to execute the Stored Procedure.
In the Table panel of the application's Design Mode, click on the Actions tab in the left sub-panel.
In the Actions sub-panel, there is a list of triggers called Action Types.
You can specify when the application should run a Stored Procedure through the Action Types:
Pre Save Executes the Stored Procedure before saving the new row.
Post Save Executes the Stored Procedure after saving the new row.
Pre Update Executes the Stored Procedure before updating a row.
Post Update Executes the Stored Procedure after updating the row.
Pre Remove Executes the Stored Procedure before removing the row.
Post Remove Executes the Stored Procedure after removing the row.
Turn on all the Enabled toggle switches, exception made the Post Remove.
Save your changes by clicking on the Save button.
Success
Every time you will add or edit an order in Warehouse Orders, the Stored Procedure will update the items' stock in Warehouse Stock.
If the requested quantity goes above the available stock, the application doesn't save the change and warns the user.