From 39e36b829563b727c5d95b17a2e94331c83ab0e6 Mon Sep 17 00:00:00 2001 From: Raymond Date: Tue, 31 May 2022 17:37:49 +0000 Subject: [PATCH 1/5] chore(ut-rule) added create, accept, discard, reject APP-1186 --- .gitignore | 1 + api/script/index.js | 15 + .../schema/350-rule.conditionUnapproved.sql | 17 + .../350-rule.conditionUnapprovedActor.sql | 11 + .../350-rule.conditionUnapprovedItem.sql | 11 + .../350-rule.conditionUnapprovedProperty.sql | 12 + api/sql/schema/360-rule.limitUnapproved.sql | 21 + .../schema/360-rule.splitNameUnapproved.sql | 11 + .../370-rule.splitAssignmentUnapproved.sql | 14 + .../schema/370-rule.splitRangeUnapproved.sql | 22 + .../380-rule.splitAnalyticUnapproved.sql | 11 + .../schema/750-rule.rule.addUnapproved.sql | 268 +++++++++++ api/sql/schema/750-rule.rule.approve.sql | 344 ++++++++++++++ .../schema/750-rule.rule.deleteUnapproved.sql | 93 ++++ api/sql/schema/750-rule.rule.discard.sql | 109 +++++ api/sql/schema/750-rule.rule.fetch.sql | 277 ++++++++---- api/sql/schema/750-rule.rule.get.sql | 201 +++++++++ api/sql/schema/750-rule.rule.reject.sql | 148 +++++++ api/sql/schema/751-rule.alter.sql | 89 ++++ package.json | 3 +- portal/index.stories.old.js | 11 + ui/react/components/Grid/index.js | 57 ++- ui/react/configuration/reducers.js | 4 + ui/react/pages/RuleProfile/Approve/index.js | 418 ++++++++++++++++++ ui/react/pages/RuleProfile/actionTypes.js | 10 + ui/react/pages/RuleProfile/actions.js | 85 +++- .../pages/RuleProfile/markerCheckerHelper.js | 182 ++++++++ ui/react/pages/RuleProfile/reducer.js | 50 ++- ui/react/pages/RuleProfile/reducerHelper.js | 29 +- ui/react/pages/Rules/index.js | 51 ++- ui/react/pages/index.js | 3 +- ui/react/registerRoutes.js | 1 + ui/react/routes.js | 3 +- validations/index.js | 7 +- validations/rule/rule.rule.addUnapproved.js | 10 + validations/rule/rule.rule.approve.js | 12 + validations/rule/rule.rule.discard.js | 12 + validations/rule/rule.rule.get.js | 10 + validations/rule/rule.rule.reject.js | 13 + 39 files changed, 2517 insertions(+), 129 deletions(-) create mode 100644 api/sql/schema/350-rule.conditionUnapproved.sql create mode 100644 api/sql/schema/350-rule.conditionUnapprovedActor.sql create mode 100644 api/sql/schema/350-rule.conditionUnapprovedItem.sql create mode 100644 api/sql/schema/350-rule.conditionUnapprovedProperty.sql create mode 100644 api/sql/schema/360-rule.limitUnapproved.sql create mode 100644 api/sql/schema/360-rule.splitNameUnapproved.sql create mode 100644 api/sql/schema/370-rule.splitAssignmentUnapproved.sql create mode 100644 api/sql/schema/370-rule.splitRangeUnapproved.sql create mode 100644 api/sql/schema/380-rule.splitAnalyticUnapproved.sql create mode 100644 api/sql/schema/750-rule.rule.addUnapproved.sql create mode 100644 api/sql/schema/750-rule.rule.approve.sql create mode 100644 api/sql/schema/750-rule.rule.deleteUnapproved.sql create mode 100644 api/sql/schema/750-rule.rule.discard.sql create mode 100644 api/sql/schema/750-rule.rule.get.sql create mode 100644 api/sql/schema/750-rule.rule.reject.sql create mode 100644 api/sql/schema/751-rule.alter.sql create mode 100644 ui/react/pages/RuleProfile/Approve/index.js create mode 100644 ui/react/pages/RuleProfile/markerCheckerHelper.js create mode 100644 validations/rule/rule.rule.addUnapproved.js create mode 100644 validations/rule/rule.rule.approve.js create mode 100644 validations/rule/rule.rule.discard.js create mode 100644 validations/rule/rule.rule.get.js create mode 100644 validations/rule/rule.rule.reject.js diff --git a/.gitignore b/.gitignore index 1e3d82ec..3cd7e22c 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ npm-debug.* package-lock.json yarn.lock .scannerwork +.lint/ \ No newline at end of file diff --git a/api/script/index.js b/api/script/index.js index a3423a15..ab2e4b6f 100644 --- a/api/script/index.js +++ b/api/script/index.js @@ -65,6 +65,21 @@ module.exports = function rule() { }).then(function(transformedData) { return { data: transformedData }; }); + }, + 'rule.rule.addUnapproved': function(msg, $meta) { + return this.bus.importMethod('db/rule.rule.addUnapproved')(msg, $meta); + }, + 'rule.rule.get': function(msg, $meta) { + return this.bus.importMethod('db/rule.rule.get')(msg, $meta); + }, + 'rule.rule.approve': function(msg, $meta) { + return this.bus.importMethod('db/rule.rule.approve')(msg, $meta); + }, + 'rule.rule.reject': function(msg, $meta) { + return this.bus.importMethod('db/rule.rule.reject')(msg, $meta); + }, + 'rule.rule.discard': function(msg, $meta) { + return this.bus.importMethod('db/rule.rule.discard')(msg, $meta); } }; }; diff --git a/api/sql/schema/350-rule.conditionUnapproved.sql b/api/sql/schema/350-rule.conditionUnapproved.sql new file mode 100644 index 00000000..a2b5d88d --- /dev/null +++ b/api/sql/schema/350-rule.conditionUnapproved.sql @@ -0,0 +1,17 @@ +CREATE TABLE [rule].[conditionUnapproved] ( + conditionId INT IDENTITY(1000, 1) NOT NULL, + [priority] INT, + operationStartDate DATETIME, + operationEndDate DATETIME, + sourceAccountId NVARCHAR(255), + destinationAccountId NVARCHAR(255), + isDeleted BIT NOT NULL DEFAULT(0), -- a flag to show if the rule is deleted, e.g. 1 - Deleted + createdBy BIGINT NULL, -- id of the actor + createdOn DATETIME2 (0) NULL, -- date of the rule created + updatedBy BIGINT NULL, -- id of the actor + updatedOn DATETIME2 (0) NULL, -- date of the rule updated + status VARCHAR(20) NULL DEFAULT('pending'), + rejectReason VARCHAR(255) NULL, + CONSTRAINT [pkRuleConditionUnapproved] PRIMARY KEY CLUSTERED ([conditionId] ASC), + CONSTRAINT fkRuleConditionUnapproved_status FOREIGN KEY(status) REFERENCES [core].[status] (statusId) +) diff --git a/api/sql/schema/350-rule.conditionUnapprovedActor.sql b/api/sql/schema/350-rule.conditionUnapprovedActor.sql new file mode 100644 index 00000000..ac1081d0 --- /dev/null +++ b/api/sql/schema/350-rule.conditionUnapprovedActor.sql @@ -0,0 +1,11 @@ +CREATE TABLE [rule].[conditionActorUnapproved] ( + conditionId INT NOT NULL, + factor CHAR(2) NOT NULL, + actorId BIGINT NOT NULL, + status VARCHAR(20) NULL DEFAULT('pending'), + CONSTRAINT pkRuleConditionActorUnapproved PRIMARY KEY CLUSTERED (conditionId, factor, actorId), + CONSTRAINT fkRuleConditionActorUnapproved_conditionId FOREIGN KEY (conditionId) REFERENCES [rule].[conditionUnapproved](conditionId), + CONSTRAINT fkRuleConditionActorUnapproved_actorId FOREIGN KEY(actorId) REFERENCES [core].[actor] (actorId), + CONSTRAINT ccRuleConditionActorUnapproved_factor CHECK (factor IN ('so', 'do', 'co')), -- source organization, destination organization, channel organization + CONSTRAINT fkRuleConditionActorUnapproved_status FOREIGN KEY(status) REFERENCES [core].[status] (statusId) +) diff --git a/api/sql/schema/350-rule.conditionUnapprovedItem.sql b/api/sql/schema/350-rule.conditionUnapprovedItem.sql new file mode 100644 index 00000000..57d322ae --- /dev/null +++ b/api/sql/schema/350-rule.conditionUnapprovedItem.sql @@ -0,0 +1,11 @@ +CREATE TABLE [rule].[conditionItemUnapproved] ( + conditionId INT NOT NULL, + factor CHAR(2) NOT NULL, + itemNameId BIGINT NOT NULL, + status VARCHAR(20) NULL DEFAULT('pending'), + CONSTRAINT pkRuleConditionItemUnapproved PRIMARY KEY CLUSTERED (conditionId, factor, itemNameId), + CONSTRAINT fkRuleConditionItemUnapproved_conditionId FOREIGN KEY (conditionId) REFERENCES [rule].[conditionUnapproved](conditionId), + CONSTRAINT fkRuleConditionItemUnapproved_itemNameId FOREIGN KEY(itemNameId) REFERENCES [core].[itemName] (itemNameId), + CONSTRAINT ccRuleConditionItemUnapproved_factor CHECK (factor IN ('ss', 'ds', 'cs', 'oc', 'sc', 'dc')), -- source spatial, destination spatial, channel spatial, operation category, source category, destination category + CONSTRAINT fkRuleConditionItemUnapproved_status FOREIGN KEY(status) REFERENCES [core].[status] (statusId) +) diff --git a/api/sql/schema/350-rule.conditionUnapprovedProperty.sql b/api/sql/schema/350-rule.conditionUnapprovedProperty.sql new file mode 100644 index 00000000..7d16929d --- /dev/null +++ b/api/sql/schema/350-rule.conditionUnapprovedProperty.sql @@ -0,0 +1,12 @@ +CREATE TABLE [rule].[conditionPropertyUnapproved] ( + conditionId INT NOT NULL, + factor CHAR(2) NOT NULL, + [name] NVARCHAR(50) NOT NULL, + [value] NVARCHAR(200) NOT NULL, + status VARCHAR(20) NULL DEFAULT('pending'), + CONSTRAINT pkRuleConditionPropertyUnapproved PRIMARY KEY CLUSTERED (conditionId, factor, [name]), + CONSTRAINT fkRuleConditionPropertyUnapproved_conditionId FOREIGN KEY (conditionId) REFERENCES [rule].[conditionUnapproved](conditionId), + CONSTRAINT ccRuleConditionPropertyUnapproved_factor CHECK (factor IN ('so', 'do', 'co', 'ss', 'ds', 'cs', 'oc', 'sc', 'dc')), + -- source organization, destination organization, channel organization, source spatial, destination spatial, channel spatial, operation category, source category, destination category + CONSTRAINT fkRuleConditionPropertyUnapproved_status FOREIGN KEY(status) REFERENCES [core].[status] (statusId) +) diff --git a/api/sql/schema/360-rule.limitUnapproved.sql b/api/sql/schema/360-rule.limitUnapproved.sql new file mode 100644 index 00000000..c67d4932 --- /dev/null +++ b/api/sql/schema/360-rule.limitUnapproved.sql @@ -0,0 +1,21 @@ +CREATE TABLE [rule].[limitUnapproved] ( + limitId INT IDENTITY(1000, 1) NOT NULL, + conditionId INT NOT NULL, + currency VARCHAR(3) NOT NULL, + minAmount MONEY, + maxAmount MONEY, + maxAmountDaily MONEY, + maxCountDaily BIGINT, + maxAmountWeekly MONEY, + maxCountWeekly BIGINT, + maxAmountMonthly MONEY, + maxCountMonthly BIGINT, + [credentials] INT, + [priority] SMALLINT, + status VARCHAR(20) NULL DEFAULT('pending'), + CONSTRAINT [pkRuleLimitUnapproved] PRIMARY KEY CLUSTERED (limitId ASC), + CONSTRAINT ukRuleLimitUnapprovedConditionCurrencyPriority UNIQUE (conditionId, currency, [priority]), + CONSTRAINT ukRuleLimitUnapprovedConditionCurrencyCredentials UNIQUE (conditionId, currency, [credentials]), + CONSTRAINT [fkRuleLimitUnapproved_condition] FOREIGN KEY (conditionId) REFERENCES [rule].[conditionUnapproved](conditionId), + CONSTRAINT fkRuleLimitUnapproved_status FOREIGN KEY(status) REFERENCES [core].[status] (statusId) +) diff --git a/api/sql/schema/360-rule.splitNameUnapproved.sql b/api/sql/schema/360-rule.splitNameUnapproved.sql new file mode 100644 index 00000000..051fe7fe --- /dev/null +++ b/api/sql/schema/360-rule.splitNameUnapproved.sql @@ -0,0 +1,11 @@ +CREATE TABLE [rule].[splitNameUnapproved] ( + splitNameId INT IDENTITY(1000, 1) NOT NULL, + conditionId INT NOT NULL, + name VARCHAR(50) NOT NULL, + tag VARCHAR(max), + status VARCHAR(20) NULL DEFAULT('pending'), + CONSTRAINT [pkRuleSplitNameUnapproved] PRIMARY KEY CLUSTERED (splitNameId ASC), + CONSTRAINT [fkRuleSplitNameUnapproved_ruleCondition] FOREIGN KEY (conditionId) REFERENCES [rule].[conditionUnapproved](conditionId), + CONSTRAINT [ukRuleSplitNameUnapprovedConditionIdName] UNIQUE (conditionId, name), + CONSTRAINT fkRuleSplitNameUnapproved_status FOREIGN KEY(status) REFERENCES [core].[status] (statusId) +) diff --git a/api/sql/schema/370-rule.splitAssignmentUnapproved.sql b/api/sql/schema/370-rule.splitAssignmentUnapproved.sql new file mode 100644 index 00000000..16b6d73f --- /dev/null +++ b/api/sql/schema/370-rule.splitAssignmentUnapproved.sql @@ -0,0 +1,14 @@ +CREATE TABLE [rule].[splitAssignmentUnapproved] ( + splitAssignmentId INT IDENTITY(1000, 1) NOT NULL, + splitNameId INT NOT NULL, + debit VARCHAR(50) NOT NULL, + credit VARCHAR(50) NOT NULL, + minValue MONEY, + maxValue MONEY, + [percent] DECIMAL(9, 2), + description VARCHAR(50) NOT NULL, + status VARCHAR(20) NULL DEFAULT('pending'), + CONSTRAINT [pkRuleSplitAssignmentUnapproved] PRIMARY KEY CLUSTERED (splitAssignmentId ASC), + CONSTRAINT [fkRuleSplitAssignmentUnapproved_ruleSplitName] FOREIGN KEY (splitNameId) REFERENCES [rule].[splitNameUnapproved](splitNameId), + CONSTRAINT fkRuleSplitAssignmentUnapproved_status FOREIGN KEY(status) REFERENCES [core].[status] (statusId) +) diff --git a/api/sql/schema/370-rule.splitRangeUnapproved.sql b/api/sql/schema/370-rule.splitRangeUnapproved.sql new file mode 100644 index 00000000..898e704a --- /dev/null +++ b/api/sql/schema/370-rule.splitRangeUnapproved.sql @@ -0,0 +1,22 @@ +CREATE TABLE [rule].[splitRangeUnapproved] ( + splitRangeId INT IDENTITY(1000, 1) NOT NULL, + splitNameId INT NOT NULL, + startAmount MONEY NOT NULL, + startAmountCurrency VARCHAR(3) NOT NULL, + startAmountDaily MONEY NOT NULL, + startCountDaily BIGINT NOT NULL, + startAmountWeekly MONEY NOT NULL, + startCountWeekly BIGINT NOT NULL, + startAmountMonthly MONEY NOT NULL, + startCountMonthly BIGINT NOT NULL, + isSourceAmount BIT NOT NULL, + minValue MONEY, + maxValue MONEY, + [percent] DECIMAL(9, 2), + percentBase MONEY, + status VARCHAR(20) NULL DEFAULT('pending'), + CONSTRAINT [pkRuleSplitRangeUnapproved] PRIMARY KEY CLUSTERED (splitRangeId ASC), + CONSTRAINT [ukRuleSplitRangeUnapproved_splitNameId__startAmount__startAmountCurrency] UNIQUE (splitNameId, startAmount, startAmountCurrency, startAmountDaily, startCountDaily, startAmountWeekly, startCountWeekly, startAmountMonthly, startCountMonthly), + CONSTRAINT [fkRuleSplitRangeUnapproved_ruleSplitName] FOREIGN KEY (splitNameId) REFERENCES [rule].[splitNameUnapproved](splitNameId), + CONSTRAINT fkRuleSplitRangeUnapproved_status FOREIGN KEY(status) REFERENCES [core].[status] (statusId) +) diff --git a/api/sql/schema/380-rule.splitAnalyticUnapproved.sql b/api/sql/schema/380-rule.splitAnalyticUnapproved.sql new file mode 100644 index 00000000..009a740a --- /dev/null +++ b/api/sql/schema/380-rule.splitAnalyticUnapproved.sql @@ -0,0 +1,11 @@ +CREATE TABLE [rule].[splitAnalyticUnapproved] ( + splitAnalyticId INT IDENTITY(1000, 1) NOT NULL, + splitAssignmentId INT NOT NULL, + [name] VARCHAR(50), + [value] VARCHAR(100), + status VARCHAR(20) NULL DEFAULT('pending'), + CONSTRAINT [pkRuleSplitAnalyticUnapproved] PRIMARY KEY CLUSTERED (splitAnalyticId ASC), + CONSTRAINT [ukRuleSplitAnalyticUnapproved_splitAssignmentId_name] UNIQUE (splitAssignmentId, [name]), + CONSTRAINT [fkRuleSplitAnalyticUnapproved_ruleSplitName] FOREIGN KEY (splitAssignmentId) REFERENCES [rule].[splitAssignmentUnapproved](splitAssignmentId), + CONSTRAINT fkRuleSplitAnalyticUnapproved_status FOREIGN KEY(status) REFERENCES [core].[status] (statusId) +) diff --git a/api/sql/schema/750-rule.rule.addUnapproved.sql b/api/sql/schema/750-rule.rule.addUnapproved.sql new file mode 100644 index 00000000..034ef6ff --- /dev/null +++ b/api/sql/schema/750-rule.rule.addUnapproved.sql @@ -0,0 +1,268 @@ +ALTER PROCEDURE [rule].[rule.addUnapproved] + @condition [rule].conditionUnapprovedTT READONLY, + @conditionActor [rule].conditionActorUnapprovedTT READONLY, + @conditionItem [rule].conditionItemUnapprovedTT READONLY, + @conditionProperty [rule].conditionPropertyUnapprovedTT READONLY, + @limit [rule].limitUnapprovedTT READONLY, + @split XML, + @meta core.metaDataTT READONLY -- information for the logged user +AS +DECLARE @userId BIGINT = (SELECT [auth.actorId] FROM @meta) +DECLARE @splitName [rule].splitNameUnapprovedTT, + @splitAssignment [rule].splitAssignmentUnapprovedTT, + @conditionId INT +BEGIN TRY + + IF EXISTS + ( + SELECT [priority] + FROM [rule].condition + WHERE [priority] = (SELECT [priority] FROM @condition) + AND isDeleted = 0 + ) + OR + EXISTS + ( + SELECT [priority] + FROM [rule].conditionUnapproved + WHERE [priority] = (SELECT [priority] FROM @condition) + ) + BEGIN + RAISERROR ('rule.duplicatedPriority', 16, 1) + END + + BEGIN TRANSACTION + + INSERT INTO [rule].conditionUnapproved( + [priority], + operationStartDate, + operationEndDate, + sourceAccountId, + destinationAccountId, + createdOn, + createdBy, + status) + SELECT + [priority], + operationStartDate, + operationEndDate, + sourceAccountId, + destinationAccountId, + GETUTCDATE(), + ISNULL(createdBy, @userId), + 'pending' + FROM @condition; + + SET @conditionId = SCOPE_IDENTITY() + + INSERT INTO [rule].conditionActorUnapproved + ( + conditionId, + factor, + actorId, + status + ) + SELECT + @conditionId, + factor, + actorId, + 'pending' + FROM @conditionActor + + INSERT INTO [rule].conditionItemUnapproved + ( + conditionId, + factor, + itemNameId, + status + ) + SELECT + @conditionId, + factor, + itemNameId, + 'pending' + FROM @conditionItem + + INSERT INTO [rule].conditionPropertyUnapproved + ( + conditionId, + factor, + name, + value, + status + ) + SELECT + @conditionId, + factor, + name, + value, + 'pending' + FROM @conditionProperty + + INSERT INTO [rule].limitUnapproved ( + conditionId, + currency, + minAmount, + maxAmount, + maxAmountDaily, + maxCountDaily, + maxAmountWeekly, + maxCountWeekly, + maxAmountMonthly, + maxCountMonthly, + [credentials], + [priority], + status + ) + SELECT @conditionId, + [currency], + [minAmount], + [maxAmount], + [maxAmountDaily], + [maxCountDaily], + [maxAmountWeekly], + [maxCountWeekly], + [maxAmountMonthly], + [maxCountMonthly], + [credentials], + [priority], + 'pending' + FROM @limit + + MERGE INTO [rule].splitNameUnapproved + USING @split.nodes('/data/rows/splitName') AS records(r) + ON 1 = 0 + WHEN NOT MATCHED THEN + INSERT (conditionId, name, tag, status) VALUES (@conditionId, r.value('(name)[1]', 'NVARCHAR(50)'), r.value('(tag)[1]', 'NVARCHAR(max)'), 'pending') + OUTPUT INSERTED.* INTO @splitName; + + MERGE INTO [rule].splitRangeUnapproved + USING ( + SELECT + sn.splitNameId AS splitNameId, + splitRange.x.value('(startAmount)[1]', 'money') AS startAmount, + splitRange.x.value('(startAmountCurrency)[1]', 'VARCHAR(3)') AS startAmountCurrency, + ISNULL(splitRange.x.value('(./startAmountDaily/text())[1]', 'money'), 0) AS startAmountDaily, + ISNULL(splitRange.x.value('(./startCountDaily/text())[1]', 'BIGINT'), 0) AS startCountDaily, + ISNULL(splitRange.x.value('(./startAmountWeekly/text())[1]', 'money'), 0) AS startAmountWeekly, + ISNULL(splitRange.x.value('(./startCountWeekly/text())[1]', 'BIGINT'), 0) AS startCountWeekly, + ISNULL(splitRange.x.value('(./startAmountMonthly/text())[1]', 'money'), 0) AS startAmountMonthly, + ISNULL(splitRange.x.value('(./startCountMonthly/text())[1]', 'BIGINT'), 0) AS startCountMonthly, + ISNULL(splitRange.x.value('(isSourceAmount)[1]', 'BIT'), 1) AS isSourceAmount, + splitRange.x.value('(minValue)[1]', 'money') AS minValue, + splitRange.x.value('(maxValue)[1]', 'money') AS maxValue, + splitRange.x.value('(percent)[1]', 'money') AS [percent], + splitRange.x.value('(percentBase)[1]', 'money') AS percentBase, + status + FROM + @split.nodes('/data/rows/splitRange') AS splitRange(x) + JOIN + @splitName sn + ON + splitRange.x.value('(../splitName/name)[1]', 'NVARCHAR(50)') = sn.name + ) AS r + ON 1 = 0 + WHEN NOT MATCHED THEN + INSERT ( + splitNameId, + startAmount, + startAmountCurrency, + startAmountDaily, + startCountDaily, + startAmountWeekly, + startCountWeekly, + startAmountMonthly, + startCountMonthly, + isSourceAmount, + minValue, + maxValue, + [percent], + percentBase, + status) + VALUES ( + r.splitNameId, + r.startAmount, + r.startAmountCurrency, + r.startAmountDaily, + r.startCountDaily, + r.startAmountWeekly, + r.startCountWeekly, + r.startAmountMonthly, + r.startCountMonthly, + r.isSourceAmount, + r.minValue, + r.maxValue, + r.[percent], + r.percentBase, + 'pending'); + + MERGE INTO [rule].splitAssignmentUnapproved + USING ( + SELECT + sn.splitNameId AS splitNameId, + splitAssignment.x.value('(debit)[1]', 'VARCHAR(50)') AS debit, + splitAssignment.x.value('(credit)[1]', 'VARCHAR(50)') AS credit, + splitAssignment.x.value('(minValue)[1]', 'money') AS minValue, + splitAssignment.x.value('(maxValue)[1]', 'money') AS maxValue, + splitAssignment.x.value('(percent)[1]', 'decimal') AS [percent], + splitAssignment.x.value('(description)[1]', 'VARCHAR(50)') AS description, + status + FROM + @split.nodes('/data/rows/splitAssignment') AS splitAssignment(x) + JOIN + @splitName sn + ON + splitAssignment.x.value('(../splitName/name)[1]', 'NVARCHAR(50)') = sn.name + ) AS r + ON 1 = 0 + WHEN NOT MATCHED THEN + INSERT (splitNameId, debit, credit, minValue, maxValue, [percent], description, status) + VALUES (r.splitNameId, r.debit, r.credit, r.minValue, r.maxValue, r.[percent], r.description, 'pending') + OUTPUT INSERTED.* INTO @splitAssignment; + + + MERGE INTO [rule].splitAnalyticUnapproved + USING ( + SELECT + sn.splitAssignmentId AS splitAssignmentId, + records.x.value('(name)[1]', 'NVARCHAR(50)') AS [name], + records.x.value('(value)[1]', 'NVARCHAR(150)') AS [value], + status + FROM + @split.nodes('/data/rows/splitAssignment/splitAnalytic') records(x) + JOIN + @splitAssignment sn + ON + records.x.value('(../debit)[1]', 'NVARCHAR(50)') = sn.debit + AND records.x.value('(../credit)[1]', 'NVARCHAR(50)') = sn.credit + AND records.x.value('(../description)[1]', 'NVARCHAR(50)') = sn.[description] + + ) AS r (splitAssignmentId, [name], [value], status) + ON 1 = 0 + WHEN NOT MATCHED THEN + INSERT (splitAssignmentId, [name], [value], status) + VALUES (r.splitAssignmentId, r.[name], r.[value], 'pending'); + + COMMIT TRANSACTION + + DECLARE @outcome XML = ( + SELECT + @conditionId [key], + c.priority rulePriority, + GETUTCDATE() creationDateTime + FROM + @condition c + FOR XML RAW + ) + + EXEC core.outcome @proc = @@PROCID, @outcome = @outcome, @meta = @meta + + EXEC [rule].[rule.fetch] @meta = @meta, @conditionId = @conditionId +END TRY +BEGIN CATCH + IF @@TRANCOUNT > 0 + ROLLBACK TRANSACTION + + EXEC core.error + RETURN 55555 +END CATCH diff --git a/api/sql/schema/750-rule.rule.approve.sql b/api/sql/schema/750-rule.rule.approve.sql new file mode 100644 index 00000000..5cd21c90 --- /dev/null +++ b/api/sql/schema/750-rule.rule.approve.sql @@ -0,0 +1,344 @@ +ALTER PROCEDURE [rule].[rule.approve] + @conditionId INT, + @meta core.metaDataTT READONLY -- information for the logged user +AS + +BEGIN TRY + + DECLARE @userId BIGINT = (SELECT [auth.actorId] FROM @meta) + -- checks if the user has a right to get user + DECLARE @actionID VARCHAR(100) = OBJECT_SCHEMA_NAME(@@PROCID) + '.' + OBJECT_NAME(@@PROCID), @return INT = 0 + EXEC @return = [user].[permission.check] @actionId = @actionID, @objectId = NULL, @meta = @meta + IF @return != 0 + BEGIN + RETURN 55555 + END + + IF NOT EXISTS( + SELECT 1 + FROM [rule].[condition] c + WHERE c.conditionId = @conditionId) + AND + NOT EXISTS( + SELECT 1 + FROM [rule].[conditionUnapproved] c + WHERE c.conditionId = @conditionId) + BEGIN + RAISERROR ('rule.ruleNotExists', 16, 1) + END + + BEGIN TRANSACTION + + -- handle condition + IF EXISTS(SELECT 1 FROM [rule].[conditionUnapproved] WHERE conditionId = @conditionId AND isDeleted = 1) + BEGIN + DECLARE @conditionRemoveIds core.arrayList + INSERT INTO @conditionRemoveIds + SELECT @conditionId + EXEC [rule].[rule.remove] @conditionId = @conditionRemoveIds + END + ELSE + BEGIN + IF EXISTS(SELECT 1 FROM [rule].[condition] WHERE conditionId = @conditionId) + BEGIN + UPDATE c + SET + c.updatedBy = cu.updatedBy, + c.updatedOn = cu.updatedOn, + c.status = 'approved', + c.operationStartDate = cu.operationStartDate, + c.operationEndDate = cu.operationEndDate, + c.sourceAccountId = cu.sourceAccountId, + c.priority = cu.priority + FROM [rule].[condition] c + INNER JOIN [rule].[conditionUnapproved] cu ON cu.conditionId = c.conditionId + WHERE c.conditionId = @conditionId + END + ELSE + BEGIN + SET IDENTITY_INSERT [rule].[condition] ON -- allow conditionId to be inserted in the condition table + INSERT INTO [rule].[condition] (conditionId, priority, status, operationStartDate, operationEndDate, sourceAccountId, isDeleted, createdBy, updatedBy) + SELECT cu.conditionId, cu.priority, 'approved', cu.operationStartDate, cu.operationEndDate, cu.sourceAccountId, 0, cu.createdBy, cu.updatedBy + FROM [rule].[conditionUnapproved] cu + WHERE cu.conditionId = @conditionId + SET IDENTITY_INSERT [rule].[condition] OFF + END + END + + + + -- handle condition actor + IF EXISTS(SELECT 1 FROM [rule].[conditionActor] WHERE conditionId = @conditionId) + BEGIN + UPDATE ca + SET + ca.factor = cau.factor, + ca.actorId = cau.actorId, + ca.status = 'approved' + FROM [rule].[conditionActor] ca + INNER JOIN [rule].[conditionActorUnapproved] cau ON cau.conditionId = ca.conditionId + WHERE ca.conditionId = @conditionId + END + ELSE + BEGIN + INSERT INTO [rule].[conditionActor] (conditionId, factor, actorId, status) + SELECT cau.conditionId, cau.factor, cau.actorId, 'approved' + FROM [rule].[conditionActorUnapproved] cau + WHERE cau.conditionId = @conditionId + END + + + + -- handle condition item + IF EXISTS(SELECT 1 FROM [rule].[conditionItem] WHERE conditionId = @conditionId) + BEGIN + UPDATE ca + SET + ca.factor = cau.factor, + ca.itemNameId = cau.itemNameId, + ca.status = 'approved' + FROM [rule].[conditionItem] ca + INNER JOIN [rule].[conditionItemUnapproved] cau ON cau.conditionId = ca.conditionId + WHERE ca.conditionId = @conditionId + END + ELSE + BEGIN + INSERT INTO [rule].[conditionItem] (conditionId, factor, itemNameId, status) + SELECT ciu.conditionId, ciu.factor, ciu.itemNameId, 'approved' + FROM [rule].[conditionItemUnapproved] ciu + WHERE ciu.conditionId = @conditionId + END + + + + -- handle condition property + IF EXISTS(SELECT 1 FROM [rule].[conditionProperty] WHERE conditionId = @conditionId) + BEGIN + UPDATE ca + SET + ca.factor = cau.factor, + ca.name = cau.name, + ca.value = cau.value, + ca.status = 'approved' + FROM [rule].[conditionProperty] ca + INNER JOIN [rule].[conditionPropertyUnapproved] cau ON cau.conditionId = ca.conditionId + WHERE ca.conditionId = @conditionId + END + ELSE + BEGIN + INSERT INTO [rule].[conditionProperty] (conditionId, factor, name, value, status) + SELECT cai.conditionId, cai.factor, cai.name, cai.value, 'approved' + FROM [rule].[conditionPropertyUnapproved] cai + WHERE cai.conditionId = @conditionId + END + + + + -- handle limit + IF EXISTS(SELECT 1 FROM [rule].[limit] WHERE conditionId = @conditionId) + BEGIN + UPDATE ca + SET + ca.currency = cau.currency, + ca.minAmount = cau.minAmount, + ca.maxAmount = cau.maxAmount, + ca.maxAmountDaily = cau.maxAmountDaily, + ca.maxCountDaily = cau.maxCountDaily, + ca.maxAmountWeekly = cau.maxAmountWeekly, + ca.maxCountWeekly = cau.maxCountWeekly, + ca.maxAmountMonthly = cau.maxAmountMonthly, + ca.maxCountMonthly = cau.maxCountMonthly, + ca.credentials = cau.credentials, + ca.priority = cau.priority, + ca.status = 'approved' + FROM [rule].limit ca + INNER JOIN [rule].[limitUnapproved] cau ON cau.conditionId = ca.conditionId + WHERE ca.conditionId = @conditionId + END + ELSE + BEGIN + SET IDENTITY_INSERT [rule].[limit] ON -- allow limitId to be inserted in the limit table + INSERT INTO [rule].[limit] (limitId, conditionId, currency, minAmount, maxAmount, maxAmountDaily, maxCountDaily, maxAmountWeekly, maxCountWeekly, maxAmountMonthly, maxCountMonthly, [credentials], [priority], status) + SELECT + cai.limitId, + cai.conditionId, + cai.currency, + cai.minAmount, + cai.maxAmount, + cai.maxAmountDaily, + cai.maxCountDaily, + cai.maxAmountWeekly, + cai.maxCountWeekly, + cai.maxAmountMonthly, + cai.maxCountMonthly, + cai.credentials, + cai.priority, + 'approved' + FROM [rule].[limitUnapproved] cai + WHERE cai.conditionId = @conditionId + SET IDENTITY_INSERT [rule].[limit] OFF + END + + + + -- handle split analytic + IF EXISTS( + SELECT 1 FROM [rule].[splitAnalytic] sa + JOIN [rule].[splitAssignment] sp ON sp.splitAssignmentId = sa.splitAssignmentId + JOIN [rule].[splitName] sn ON sp.splitNameId = sn.splitNameId + WHERE sn.conditionId = @conditionId + ) + BEGIN + UPDATE spa + SET + spa.name = spau.name, + spa.value = spau.value, + spa.status = 'approved' + FROM [rule].[splitAnalytic] spa + INNER JOIN [rule].[splitAnalyticUnapproved] spau ON spau.splitAnalyticId = spa.splitAnalyticId + INNER JOIN [rule].[splitAssignmentUnapproved] sp ON sp.splitAssignmentId = spau.splitAssignmentId + INNER JOIN [rule].[splitNameUnapproved] sn ON sp.splitNameId = sp.splitNameId + WHERE sn.conditionId = @conditionId + END + ELSE + BEGIN + SET IDENTITY_INSERT [rule].[splitAnalytic] ON -- allow splitAnalyticId to be inserted in the split analytic table + INSERT INTO [rule].[splitAnalytic] (splitAnalyticId, splitAssignmentId, name, value, status) + SELECT spau.splitAnalyticId, spau.splitAssignmentId, spau.name, spau.value, 'approved' + FROM [rule].[splitAnalyticUnapproved] spau + JOIN [rule].[splitAssignmentUnapproved] sp ON sp.splitAssignmentId = spau.splitAssignmentId + JOIN [rule].[splitNameUnapproved] sn ON sp.splitNameId = sn.splitNameId + WHERE sn.conditionId = @conditionId + SET IDENTITY_INSERT [rule].[splitAnalytic] OFF + END + + + + -- handle split name + IF EXISTS(SELECT 1 FROM [rule].[splitName] WHERE conditionId = @conditionId) + BEGIN + UPDATE sn + SET + sn.name = snu.name, + sn.tag = snu.tag, + sn.status = 'approved' + FROM [rule].[splitName] sn + INNER JOIN [rule].[splitNameUnapproved] snu ON snu.splitNameId = sn.splitNameId + WHERE sn.conditionid = @conditionId + END + ELSE + BEGIN + SET IDENTITY_INSERT [rule].[splitName] ON -- allow split name to be inserted in the split name table + INSERT INTO [rule].[splitName] (splitNameId, conditionId, name, tag, status) + SELECT snu.splitNameId, snu.conditionId, snu.name, snu.tag, 'approved' + FROM [rule].[splitNameUnapproved] snu + WHERE snu.conditionId = @conditionId + SET IDENTITY_INSERT [rule].[splitName] OFF + END + + + + -- handle split range + IF EXISTS( + SELECT 1 FROM [rule].[splitRange] sr + JOIN [rule].[splitName] sn ON sn.splitNameId = sr.splitNameId + WHERE sn.conditionId = @conditionId + ) + BEGIN + UPDATE sr + SET + sr.startAmount = sru.startAmount, + sr.startAmountCurrency = sru.startAmountCurrency, + sr.startAmountDaily = sru.startAmountDaily, + sr.startCountDaily = sru.startCountDaily, + sr.startAmountWeekly = sru.startAmountWeekly, + sr.startCountWeekly = sru.startCountWeekly, + sr.startAmountMonthly = sru.startAmountMonthly, + sr.startCountMonthly = sru.startCountMonthly, + sr.isSourceAmount = sru.isSourceAmount, + sr.minValue = sru.minValue, + sr.maxValue = sru.maxValue, + sr.[percent] = sru.[percent], + sr.percentBase = sru.percentBase, + sr.status = 'approved' + FROM [rule].[splitRange] sr + INNER JOIN [rule].[splitRangeUnapproved] sru ON sru.splitRangeId = sr.splitRangeId + INNER JOIN [rule].[splitNameUnapproved] sn ON sn.splitNameId = sr.splitNameId + WHERE sn.conditionId = @conditionId + END + ELSE + BEGIN + SET IDENTITY_INSERT [rule].[splitRange] ON --allow split range id to be inserted + INSERT INTO [rule].[splitRange] ( splitRangeId, startAmount, startAmountCurrency, startAmountDaily, startCountDaily, startAmountWeekly, startCountWeekly, startAmountMonthly, startCountMonthly, isSourceAmount, minValue, maxValue, [percent], percentBase, splitNameId, status) + SELECT + sr.splitRangeId, + sr.startAmount, + sr.startAmountCurrency, + sr.startAmountDaily, + sr.startCountDaily, + sr.startAmountWeekly, + sr.startCountWeekly, + sr.startAmountMonthly, + sr.startCountMonthly, + sr.isSourceAmount, + sr.minValue, + sr.maxValue, + sr.[percent], + sr.percentBase, + sr.splitNameId, + 'approved' + FROM [rule].[splitRangeUnapproved] sr + INNER JOIN [rule].[splitNameUnapproved] sn ON sn.splitNameId = sr.splitNameId + WHERE sn.conditionId = @conditionId + SET IDENTITY_INSERT [rule].[splitRange] OFF + END + + + + -- handle split assignment + IF EXISTS( + SELECT 1 FROM [rule].[splitAssignment] sa + JOIN [rule].[splitName] sn ON sn.splitNameId = sa.splitNameId + WHERE sn.conditionId = @conditionId + ) + BEGIN + UPDATE sa + SET + sa.debit = sau.debit, + sa.credit = sau.credit, + sa.minValue = sau.minValue, + sa.maxValue = sau.maxValue, + sa.[percent] = sau.[percent], + sa.description = sau.description, + sa.status = 'approved' + FROM [rule].[splitAssignment] sa + INNER JOIN [rule].[splitAssignmentUnapproved] sau ON sau.splitAssignmentId = sa.splitAssignmentId + JOIN [rule].[splitNameUnapproved] sna ON sau.splitNameId = sna.splitNameId + WHERE sna.conditionId = @conditionId + END + ELSE + BEGIN + SET IDENTITY_INSERT [rule].[splitAssignment] ON -- allow splitAssignment to be inserted in the split assignment table + INSERT INTO [rule].[splitAssignment] (splitAssignmentId, splitNameId, debit, credit, minValue, maxValue, [percent], description, status) + SELECT sa.splitAssignmentId, sa.splitNameId, sa.debit, sa.credit, sa.minValue, sa.maxValue, sa.[percent], sa.description, 'approved' + FROM [rule].[splitAssignmentUnapproved] sa + JOIN [rule].[splitNameUnapproved] sn ON sn.splitNameId = sa.splitNameId + WHERE sn.conditionId = @conditionId + SET IDENTITY_INSERT [rule].[splitAssignment] OFF + END + + + DECLARE @conditionIds core.arrayList + INSERT INTO @conditionIds + SELECT @conditionId + EXEC [rule].[rule.deleteUnapproved] @conditionId = @conditionIds + + COMMIT TRANSACTION + +END TRY +BEGIN CATCH + IF @@TRANCOUNT > 0 + ROLLBACK TRANSACTION + EXEC core.error + RETURN 55555 +END CATCH diff --git a/api/sql/schema/750-rule.rule.deleteUnapproved.sql b/api/sql/schema/750-rule.rule.deleteUnapproved.sql new file mode 100644 index 00000000..377e7093 --- /dev/null +++ b/api/sql/schema/750-rule.rule.deleteUnapproved.sql @@ -0,0 +1,93 @@ +ALTER PROCEDURE [rule].[rule.deleteUnapproved] + @conditionId core.arrayList READONLY, + @meta core.metaDataTT READONLY -- information for the user that makes the operation +AS +DECLARE @userId BIGINT = (SELECT [auth.actorId] FROM @meta) +BEGIN TRY + + BEGIN TRANSACTION + DELETE x + FROM + [rule].limitUnapproved x + JOIN + @conditionId item ON x.conditionId = item.value + + DELETE x + FROM + [rule].conditionActorUnapproved x + JOIN + @conditionId item ON x.conditionId = item.value + + DELETE x + FROM + [rule].conditionItemUnapproved x + JOIN + @conditionId item ON x.conditionId = item.value + + DELETE x + FROM + [rule].conditionPropertyUnapproved x + JOIN + @conditionId item ON x.conditionId = item.value + + DELETE + x + FROM + [rule].splitRangeUnapproved x + JOIN + [rule].splitNameUnapproved s ON s.splitNameId = x.splitNameId + JOIN + @conditionId item ON s.conditionId = item.value + + DELETE + x + FROM + [rule].splitAnalyticUnapproved x + JOIN + [rule].splitAssignmentUnapproved y ON y.splitAssignmentId = x.splitAssignmentId + JOIN + [rule].splitNameUnapproved s ON s.splitNameId = y.splitNameId + JOIN + @conditionId item ON s.conditionId = item.value + + DELETE + x + FROM + [rule].splitAssignmentUnapproved x + JOIN + [rule].splitNameUnapproved s ON s.splitNameId = x.splitNameId + JOIN + @conditionId item ON s.conditionId = item.value + + DELETE + x + FROM + [rule].splitRangeUnapproved x + JOIN + [rule].splitNameUnapproved s ON s.splitNameId = x.splitNameId + JOIN + @conditionId item ON s.conditionId = item.value + + DELETE + x + FROM + [rule].splitNameUnapproved x + JOIN + @conditionId item ON x.conditionId = item.value + + DELETE + x + FROM + [rule].conditionUnapproved x + JOIN + @conditionId item ON x.conditionId = item.value + + + COMMIT TRANSACTION +END TRY +BEGIN CATCH + IF @@TRANCOUNT > 0 + ROLLBACK TRANSACTION + EXEC core.error + RETURN 55555 +END CATCH diff --git a/api/sql/schema/750-rule.rule.discard.sql b/api/sql/schema/750-rule.rule.discard.sql new file mode 100644 index 00000000..a7ef78c7 --- /dev/null +++ b/api/sql/schema/750-rule.rule.discard.sql @@ -0,0 +1,109 @@ +ALTER PROCEDURE [rule].[rule.discard] + @conditionId INT, + @meta core.metaDataTT READONLY -- information for the logged user +AS + +BEGIN TRY + + DECLARE @userId BIGINT = (SELECT [auth.actorId] FROM @meta) + -- checks if the user has a right to get user + DECLARE @actionID VARCHAR(100) = OBJECT_SCHEMA_NAME(@@PROCID) + '.' + OBJECT_NAME(@@PROCID), @return INT = 0 + EXEC @return = [user].[permission.check] @actionId = @actionID, @objectId = NULL, @meta = @meta + IF @return != 0 + BEGIN + RETURN 55555 + END + + IF NOT EXISTS( + SELECT 1 + FROM [rule].[condition] c + WHERE c.conditionId = @conditionId) + AND + NOT EXISTS( + SELECT 1 + FROM [rule].[conditionUnapproved] c + WHERE c.conditionId = @conditionId) + BEGIN + RAISERROR ('rule.ruleNotExists', 16, 1) + END + + + + -- check if the maker and the checker are different users + IF EXISTS ( + SELECT u.updatedBy + FROM [user].[userUnapproved] u + LEFT JOIN [user].[vSystemUser] su ON su.actorId = u.updatedBy + WHERE u.actorId = @userId + AND u.updatedBy = @userId + AND su.actorId IS NULL) + RAISERROR('user.cannotPerformThisOperation', 16, 1) + + BEGIN TRANSACTION + + DECLARE @splitNameId NVARCHAR(25); + SET @splitNameId = (SELECT splitNameId FROM [rule].[splitNameUnapproved] WHERE conditionId = @conditionId ) + + + -- handle condition actor + DELETE FROM [rule].[conditionActorUnapproved] + WHERE conditionId = @conditionId + + + -- handle condition item + DELETE FROM [rule].[conditionItemUnapproved] + WHERE conditionId = @conditionId + + + + -- handle condition property + DELETE FROM [rule].[conditionPropertyUnapproved] + WHERE conditionId = @conditionId + + + -- handle limit + DELETE FROM [rule].limit + WHERE conditionId = @conditionId + + + IF @splitNameId IS NOT NULL + BEGIN + -- handle split analytic + DELETE spa + FROM [rule].[splitAnalyticUnapproved] spa + INNER JOIN [rule].[splitAssignmentUnapproved] sp ON sp.splitAssignmentId = spa.splitAssignmentId + INNER JOIN [rule].[splitNameUnapproved] sn ON sp.splitNameId = sp.splitNameId + WHERE sn.splitNameId = @splitNameId + + + -- handle split assignment + DELETE sau + FROM [rule].[splitAssignmentUnapproved] sau + INNER JOIN [rule].[splitNameUnapproved] sn ON sn.splitNameId = sau.splitNameId + WHERE sn.conditionId = @conditionId + + -- handle split range + DELETE sau + FROM [rule].[splitRangeUnapproved] sau + INNER JOIN [rule].[splitNameUnapproved] sn ON sn.splitNameId = sau.splitNameId + WHERE sn.conditionId = @conditionId + + -- handle split name + DELETE FROM [rule].[splitNameUnapproved] + WHERE conditionid = @conditionId + END + + -- handle condition + DELETE FROM [rule].[conditionUnapproved] + WHERE conditionId = @conditionId + + + COMMIT TRANSACTION + +END TRY +BEGIN CATCH + IF @@TRANCOUNT > 0 + ROLLBACK TRANSACTION + EXEC core.error + RETURN 55555 +END CATCH diff --git a/api/sql/schema/750-rule.rule.fetch.sql b/api/sql/schema/750-rule.rule.fetch.sql index 6a3fe87d..9b91d443 100644 --- a/api/sql/schema/750-rule.rule.fetch.sql +++ b/api/sql/schema/750-rule.rule.fetch.sql @@ -1,26 +1,49 @@ +USE [impl-paasDev] + GO +/****** Object: StoredProcedure [rule].[rule.fetch] Script Date: 28/05/2022 12:46:10 pm ******/ +SET ANSI_NULLS ON + GO +SET QUOTED_IDENTIFIER ON + GO ALTER PROCEDURE [rule].[rule.fetch] @conditionId INT = NULL, - @operationCode NVARCHAR(200) = NULL, -- used for filtering, the code of the operation for which the rules are defined - @pageSize INT = 25, -- how many rows will be returned per page - @pageNumber INT = 1, -- which page number to display, - @meta core.metaDataTT READONLY -- information for the logged user + @pageSize INT = 25, + -- how many ROWS will be returned per page + @pageNumber INT = 1, + -- which page number to display, + @meta core.metaDataTT READONLY +-- information for the logged user AS -SET NOCOUNT ON +DECLARE @userId BIGINT = (SELECT [auth.actorId] +FROM @meta) +DECLARE @startRow INT = (@pageNumber - 1) * @pageSize + 1 +DECLARE @endRow INT = @startRow + @pageSize - 1 BEGIN - IF @conditionId IS NOT NULL AND NOT EXISTS (SELECT conditionid FROM [rule].[condition] WHERE conditionId = @conditionId) - RAISERROR ('rule.ruleNotExists', 16, 1) - DECLARE @operationId BIGINT = (SELECT itemNameId FROM core.itemName i - JOIN core.itemType it ON i.itemTypeId = it.itemTypeId - WHERE it.alias = 'operation' AND i.itemCode = @operationCode) + -- checks if the user has a right to get user + DECLARE @actionID VARCHAR(100) = OBJECT_SCHEMA_NAME(@@PROCID) + '.' + OBJECT_NAME(@@PROCID), @return INT = 0 + EXEC @return = [user].[permission.check] @actionId = @actionID, @objectId = NULL, @meta = @meta + IF @return != 0 + BEGIN + RETURN 55555 + END - DECLARE @recordsTotal INT = 0 + IF @conditionId IS NOT NULL AND NOT EXISTS (SELECT conditionId + FROM [rule].[condition] + WHERE conditionId = @conditionId) + AND + NOT EXISTS + (SELECT conditionId + FROM [rule].[conditionUnapproved] + WHERE conditionId = @conditionId) + RAISERROR ('rule.ruleNotExists', 16, 1) IF OBJECT_ID('tempdb..#RuleConditions') IS NOT NULL DROP TABLE #RuleConditions - CREATE TABLE #RuleConditions ( + CREATE TABLE #RuleConditions + ( conditionId INT, [priority] INT, operationEndDate DATETIME, @@ -28,24 +51,58 @@ BEGIN sourceAccountId NVARCHAR(255), destinationAccountId NVARCHAR(255), rowNum INT, - recordsTotal INT) - - INSERT INTO #RuleConditions(conditionId, [priority], operationEndDate, operationStartDate, sourceAccountId, destinationAccountId, rowNum, recordsTotal) - SELECT rc.conditionId, rc.[priority], - rc.operationEndDate, rc.operationStartDate, - rc.sourceAccountId, rc.destinationAccountId, - ROW_NUMBER() OVER(ORDER BY rc.[priority] ASC) AS rowNum, - COUNT(*) OVER(PARTITION BY 1) AS recordsTotal - FROM [rule].condition rc - WHERE (@conditionId IS NULL OR rc.conditionId = @conditionId ) - AND rc.isDeleted = 0 - AND (@operationId IS NULL - OR EXISTS(SELECT * FROM [rule].conditionItem ri WHERE ri.conditionId = rc.conditionId AND ri.factor = 'oc' AND ri.itemNameId = @operationId)) - ORDER BY rc.[priority] ASC - OFFSET (@pageNumber - 1) * @PageSize ROWS - FETCH NEXT @PageSize ROWS ONLY - - SET @recordsTotal = ISNULL((SELECT TOP 1 recordsTotal FROM #RuleConditions), 0) + status VARCHAR(20), + recordsTotal INT + ); + WITH + CTE + AS + ( + SELECT rc.conditionId, + rc.[priority], + rc.operationEndDate, + rc.operationStartDate, + rc.sourceAccountId, + rc.destinationAccountId, + rc.status, + ROW_NUMBER() OVER(ORDER BY rc.[priority] ASC) AS rowNum, + COUNT(*) OVER(PARTITION BY 1) AS recordsTotal + FROM + [rule].condition rc + WHERE (@conditionId IS NULL OR rc.conditionId = @conditionId ) AND rc.isDeleted = 0 + + UNION ALL + + SELECT + urc.conditionId, + urc.[priority], + urc.operationEndDate, + urc.operationStartDate, + urc.sourceAccountId, + urc.destinationAccountId, + urc.status, + ROW_NUMBER() OVER(ORDER BY urc.[priority] ASC) AS rowNum, + COUNT(*) OVER(PARTITION BY 1) AS recordsTotal + FROM + [rule].conditionUnapproved urc + WHERE (@conditionId IS NULL OR urc.conditionId = @conditionId ) AND urc.isDeleted = 0 + ) + + INSERT INTO #RuleConditions + ( conditionId, [priority], operationEndDate, operationStartDate, sourceAccountId, destinationAccountId, rowNum, recordsTotal, status) + SELECT + conditionId, + [priority], + operationEndDate, + operationStartDate, + sourceAccountId, + destinationAccountId, + rowNum, + recordsTotal, + status + FROM CTE + WHERE (rowNum BETWEEN @startRow AND @endRow) OR (@startRow >= recordsTotal AND RowNum > recordsTotal - (recordsTotal % @pageSize)) + SELECT 'condition' AS resultSetName SELECT @@ -54,91 +111,163 @@ BEGIN rct.[operationEndDate], rct.[operationStartDate], rct.[sourceAccountId], - rct.[destinationAccountId] + rct.[destinationAccountId], + rct.status FROM #RuleConditions rct - ORDER BY rct.[priority] ASC SELECT 'conditionActor' AS resultSetName SELECT - ca.*, a.actorType AS [type], co.organizationName + cca.conditionId, cca.factor, cca.actorId, cca.status, + CASE WHEN @conditionId IS NOT NULL THEN CAST(cca.actorId AS NVARCHAR) ELSE org.organizationName END AS actorId, a.actorType AS [type] + -- ca.*, a.actorType AS [type] FROM - [rule].conditionActor ca - JOIN - #RuleConditions rct ON rct.conditionId = ca.conditionId - JOIN - core.actor a ON a.actorId = ca.actorId - LEFT JOIN [customer].[organization] co ON co.actorId = ca.actorId + ( + SELECT ca.conditionId, ca.status, ca.factor, ca.actorId + FROM [rule].conditionActor ca + + UNION ALL + + SELECT cau.conditionId, cau.status, cau.factor, cau.actorId + FROM [rule].conditionActorUnapproved cau + + ) cca + JOIN #RuleConditions rct ON rct.conditionId = cca.conditionId + JOIN core.actor a ON a.actorId = cca.actorId + JOIN customer.organization org ON org.actorId = cca.actorId + WHERE + @conditionId IS NULL OR cca.conditionId = @conditionId SELECT 'conditionItem' AS resultSetName SELECT - c.*, t.alias AS [type], t.name AS itemTypeName, i.itemName + c.conditionId, c.factor, c.status, t.alias AS [type], t.name AS itemTypeName, i.itemName AS itemName FROM - [rule].conditionItem c - JOIN - #RuleConditions rct ON rct.conditionId = c.conditionId - JOIN - core.itemName i ON i.itemNameId = c.itemNameId - JOIN - core.itemType t ON t.itemTypeId = i.itemTypeId + ( + SELECT ci.conditionId, ci.factor, ci.status, ci.itemNameId + FROM [rule].conditionItem ci + + UNION ALL + + SELECT ciu.conditionId, ciu.factor, ciu.status, ciu.itemNameId + FROM [rule].conditionItemUnapproved ciu + ) c + JOIN #RuleConditions rct ON rct.conditionId = c.conditionId + JOIN core.itemName i ON i.itemNameId = c.itemNameId + JOIN core.itemType t ON t.itemTypeId = i.itemTypeId + WHERE + @conditionId IS NULL OR c.conditionId = @conditionId + SELECT 'conditionProperty' AS resultSetName SELECT cp.* FROM - [rule].conditionProperty cp - JOIN - #RuleConditions rct ON rct.conditionId = cp.conditionId + ( + SELECT * + FROM [rule].conditionProperty + + UNION ALL + + SELECT * + FROM [rule].conditionPropertyUnapproved + ) cp + JOIN #RuleConditions rct ON rct.conditionId = cp.conditionId + WHERE + @conditionId IS NULL OR cp.conditionId = @conditionId SELECT 'splitName' AS resultSetName SELECT sn.* FROM - [rule].splitName sn - JOIN - #RuleConditions rct ON rct.conditionId = sn.conditionId + ( + SELECT * + FROM [rule].splitName + + UNION ALL + + SELECT * + FROM [rule].splitNameUnapproved + ) sn + JOIN #RuleConditions rct ON rct.conditionId = sn.conditionId + WHERE + @conditionId IS NULL OR sn.conditionId = @conditionId + + SELECT 'splitRange' AS resultSetName SELECT sr.* FROM - [rule].splitRange sr - JOIN - [rule].splitName sn ON sn.splitNameId = sr.splitNameId - JOIN - #RuleConditions rct ON rct.conditionId = sn.conditionId + ( + SELECT * + FROM [rule].splitRange + + UNION ALL + + SELECT * + FROM [rule].splitRangeUnapproved + ) sr + LEFT JOIN [rule].splitNameUnapproved snu ON snu.splitNameId = sr.splitNameId + LEFT JOIN [rule].splitName sn ON sn.splitNameId = sr.splitNameId + WHERE @conditionId IS NULL OR sn.conditionId = @conditionId OR snu.conditionId = @conditionId SELECT 'splitAssignment' AS resultSetName SELECT sa.* FROM - [rule].splitAssignment sa - JOIN - [rule].splitName sn ON sn.splitNameId = sa.splitNameId - JOIN - #RuleConditions rct ON rct.conditionId = sn.conditionId + ( + SELECT * + FROM [rule].splitAssignment + + UNION ALL + + SELECT * + FROM [rule].splitAssignmentUnapproved + ) sa + LEFT JOIN [rule].splitNameUnapproved snu ON snu.splitNameId = sa.splitNameId + LEFT JOIN [rule].splitName sn ON sn.splitNameId = sa.splitNameId + WHERE @conditionId IS NULL OR sn.conditionId = @conditionId OR snu.conditionId = @conditionId SELECT 'limit' AS resultSetName SELECT l.* FROM - [rule].limit l - JOIN - #RuleConditions rct ON rct.conditionId = l.conditionId + ( + SELECT * FROM [rule].limit + + UNION ALL + + SELECT * + FROM [rule].limitUnapproved + ) l + JOIN #RuleConditions rct ON rct.conditionId = l.conditionId + WHERE + @conditionId IS NULL OR l.conditionId = @conditionId SELECT 'splitAnalytic' AS resultSetName SELECT san.* FROM - [rule].splitAnalytic san - JOIN - [rule].splitAssignment sa ON sa.splitAssignmentId = san.splitAssignmentId - JOIN - [rule].splitName sn ON sn.splitNameId = sa.splitNameId - JOIN - #RuleConditions rct ON rct.conditionId = sn.conditionId + ( + SELECT * + FROM [rule].splitAnalytic + + UNION ALL + + SELECT * + FROM [rule].splitAnalyticUnapproved ) san + JOIN [rule].splitAssignmentUnapproved sa ON sa.splitAssignmentId = san.splitAssignmentId + JOIN [rule].splitNameUnapproved sn ON sn.splitNameId = sa.splitNameId + JOIN #RuleConditions rct ON rct.conditionId = sn.conditionId + WHERE + @conditionId IS NULL OR sn.conditionId = @conditionId SELECT 'pagination' AS resultSetName - SELECT @pageSize AS pageSize, @recordsTotal AS recordsTotal, @pageNumber AS pageNumber, (@recordsTotal - 1) / @pageSize + 1 AS pagesTotal + SELECT TOP 1 + @pageSize AS pageSize, + recordsTotal AS recordsTotal, + CASE WHEN @pageNumber < (recordsTotal - 1) / @pageSize + 1 THEN @pageNumber ELSE (recordsTotal - 1) / @pageSize + 1 END AS pageNumber, + (recordsTotal - 1) / @pageSize + 1 AS pagesTotal + FROM #RuleConditions DROP TABLE #RuleConditions END diff --git a/api/sql/schema/750-rule.rule.get.sql b/api/sql/schema/750-rule.rule.get.sql new file mode 100644 index 00000000..9ac22e37 --- /dev/null +++ b/api/sql/schema/750-rule.rule.get.sql @@ -0,0 +1,201 @@ +ALTER PROCEDURE [rule].[rule.get] + @conditionId INT, + @meta core.metaDataTT READONLY +-- information for the logged user +AS + +BEGIN + + DECLARE @userId BIGINT = (SELECT [auth.actorId] + FROM @meta) + -- checks if the user has a right to get user + DECLARE @actionID VARCHAR(100) = OBJECT_SCHEMA_NAME(@@PROCID) + '.' + OBJECT_NAME(@@PROCID), @return INT = 0 + EXEC @return = [user].[permission.check] @actionId = @actionID, @objectId = NULL, @meta = @meta + IF @return != 0 + BEGIN + RETURN 55555 + END + + IF NOT EXISTS( + SELECT 1 + FROM [rule].condition c + WHERE c.conditionId = @conditionId) + AND + NOT EXISTS( + SELECT 1 + FROM [rule].conditionUnapproved c + WHERE c.conditionId = @conditionId) + RAISERROR ('rule.ruleNotExists', 16, 1) + + + + + SELECT 'condition' AS resultSetName, 1 single + SELECT + c.[conditionId], + c.[priority], + c.[operationEndDate], + c.[operationStartDate], + c.[sourceAccountId], + c.[destinationAccountId], + c.status, + CASE WHEN co.conditionId IS NULL THEN 1 ELSE 0 END AS [isNew] + FROM [rule].condition c + LEFT JOIN [rule].conditionUnapproved co ON co.conditionId = c.conditionId + WHERE c.conditionId = @conditionId + + SELECT 'conditionUnapproved' AS resultSetName, 1 single + SELECT + c.[conditionId], + c.[priority], + c.[operationEndDate], + c.[operationStartDate], + c.[sourceAccountId], + c.[destinationAccountId], + c.[rejectReason], + c.status, + CASE WHEN co.conditionId IS NULL THEN 1 ELSE 0 END AS [isNew] + FROM [rule].conditionUnapproved c + LEFT JOIN [rule].[condition] co ON co.conditionId = c.conditionId + WHERE c.conditionId = @conditionId + + + + + SELECT 'conditionActor' AS resultSetName + SELECT + cca.conditionId, cca.factor, cca.actorId, cca.status, org.organizationName AS actorId, a.actorType AS [type] -- ca.*, a.actorType AS [type] + FROM [rule].conditionActor cca + JOIN + core.actor a ON a.actorId = cca.actorId + JOIN + customer.organization org ON org.actorId = cca.actorId + WHERE cca.conditionId = @conditionId + + SELECT 'conditionActorUnapproved' AS resultSetName + SELECT + cca.conditionId, cca.factor, cca.actorId, cca.status, org.organizationName AS actorId, a.actorType AS [type] -- ca.*, a.actorType AS [type] + FROM [rule].conditionActorUnapproved cca + JOIN + core.actor a ON a.actorId = cca.actorId + JOIN + customer.organization org ON org.actorId = cca.actorId + WHERE cca.conditionId = @conditionId + + + + SELECT 'conditionItem' AS resultSetName + SELECT + c.conditionId, c.factor, c.status, t.alias AS [type], t.name AS itemTypeName, i.itemName AS itemName + FROM [rule].conditionItem AS c + JOIN core.itemName i ON i.itemNameId = c.itemNameId + JOIN core.itemType t ON t.itemTypeId = i.itemTypeId + WHERE c.conditionId = @conditionId + + + SELECT 'conditionItemUnapproved' AS resultSetName + SELECT + c.conditionId, c.factor, c.status, t.alias AS [type], t.name AS itemTypeName, i.itemName AS itemName + FROM [rule].conditionItemUnapproved AS c + JOIN core.itemName i ON i.itemNameId = c.itemNameId + JOIN core.itemType t ON t.itemTypeId = i.itemTypeId + WHERE c.conditionId = @conditionId + + + + SELECT 'conditionProperty' AS resultSetName + SELECT + cp.* + FROM [rule].conditionProperty cp + WHERE cp.conditionId = @conditionId + + + SELECT 'conditionPropertyUnapproved' AS resultSetName + SELECT + cp.* + FROM [rule].conditionPropertyUnapproved cp + WHERE cp.conditionId = @conditionId + + + + + SELECT 'splitName' AS resultSetName + SELECT + sn.* + FROM [rule].splitName sn + WHERE sn.conditionId = @conditionId + + SELECT 'splitNameUnapproved' AS resultSetName + SELECT + sn.* + FROM [rule].splitNameUnapproved sn + WHERE sn.conditionId = @conditionId + + + + SELECT 'splitRange' AS resultSetName + SELECT + sr.* + FROM [rule].splitRange sr + JOIN [rule].splitName sn ON sn.splitNameId = sr.splitNameId + WHERE sn.conditionId = @conditionId + + SELECT 'splitRangeUnapproved' AS resultSetName + SELECT + sr.* + FROM [rule].splitRangeUnapproved sr + JOIN [rule].splitNameUnapproved sn ON sn.splitNameId = sr.splitNameId + WHERE sn.conditionId = @conditionId + + + + + SELECT 'splitAssignment' AS resultSetName + SELECT + sa.* + FROM [rule].splitAssignment sa + JOIN [rule].splitName sn ON sn.splitNameId = sa.splitNameId + WHERE sn.conditionId = @conditionId + + SELECT 'splitAssignmentUnapproved' AS resultSetName + SELECT + sa.* + FROM [rule].splitAssignmentUnapproved sa + JOIN [rule].splitNameUnapproved sn ON sn.splitNameId = sa.splitNameId + WHERE sn.conditionId = @conditionId + + + + + SELECT 'limit' AS resultSetName + SELECT + l.* + FROM [rule].limit l + WHERE l.conditionId = @conditionId + + SELECT 'limitUnapproved' AS resultSetName + SELECT + l.* + FROM [rule].limitUnapproved l + WHERE l.conditionId = @conditionId + + + + + SELECT 'splitAnalytic' AS resultSetName + SELECT + san.* + FROM [rule].splitAnalytic san + JOIN [rule].splitAssignment sa ON sa.splitAssignmentId = san.splitAssignmentId + JOIN [rule].splitName sn ON sn.splitNameId = sa.splitNameId + WHERE sn.conditionId = @conditionId + + SELECT 'splitAnalyticUnapproved' AS resultSetName + SELECT + san.* + FROM [rule].splitAnalyticUnapproved san + JOIN [rule].splitAssignmentUnapproved sa ON sa.splitAssignmentId = san.splitAssignmentId + JOIN [rule].splitNameUnapproved sn ON sn.splitNameId = sa.splitNameId + WHERE sn.conditionId = @conditionId + +END diff --git a/api/sql/schema/750-rule.rule.reject.sql b/api/sql/schema/750-rule.rule.reject.sql new file mode 100644 index 00000000..e8faa72c --- /dev/null +++ b/api/sql/schema/750-rule.rule.reject.sql @@ -0,0 +1,148 @@ +ALTER PROCEDURE [rule].[rule.reject] + @conditionId INT, + @rejectReason NVARCHAR(MAX), -- the reason the user was rejected by the checker + @meta core.metaDataTT READONLY -- information for the logged user +AS + +BEGIN TRY + + DECLARE @userId BIGINT = (SELECT [auth.actorId] FROM @meta) + -- checks if the user has a right to get user + DECLARE @actionID VARCHAR(100) = OBJECT_SCHEMA_NAME(@@PROCID) + '.' + OBJECT_NAME(@@PROCID), @return INT = 0 + EXEC @return = [user].[permission.check] @actionId = @actionID, @objectId = NULL, @meta = @meta + IF @return != 0 + BEGIN + RETURN 55555 + END + + IF NOT EXISTS( + SELECT 1 + FROM [rule].[condition] c + WHERE c.conditionId = @conditionId) + AND + NOT EXISTS( + SELECT 1 + FROM [rule].[conditionUnapproved] c + WHERE c.conditionId = @conditionId) + BEGIN + RAISERROR ('rule.ruleNotExists', 16, 1) + END + + + + -- check if the maker and the checker are different users + IF EXISTS ( + SELECT u.updatedBy + FROM [user].[userUnapproved] u + LEFT JOIN [user].[vSystemUser] su ON su.actorId = u.updatedBy + WHERE u.actorId = @userId + AND u.updatedBy = @userId + AND su.actorId IS NULL) + RAISERROR('user.cannotPerformThisOperation', 16, 1) + + BEGIN TRANSACTION + + -- handle condition + UPDATE c + SET + c.status = 'rejected', + c.rejectReason = @rejectReason + FROM [rule].[conditionUnapproved] c + WHERE c.conditionId = @conditionId + + + + + -- handle condition actor + UPDATE ca + SET + ca.status = 'rejected' + FROM [rule].[conditionActorUnapproved] ca + WHERE ca.conditionId = @conditionId + + + + -- handle condition item + UPDATE ca + SET + ca.status = 'rejected' + FROM [rule].[conditionItemUnapproved] ca + WHERE ca.conditionId = @conditionId + + + + -- handle condition property + UPDATE ca + SET + ca.status = 'rejected' + FROM [rule].[conditionPropertyUnapproved] ca + WHERE ca.conditionId = @conditionId + + + + -- handle limit + UPDATE ca + SET + ca.status = 'rejected' + FROM [rule].limit ca + WHERE ca.conditionId = @conditionId + + + + -- handle split analytic + UPDATE spa + SET + spa.status = 'rejected' + FROM [rule].[splitAnalyticUnapproved] spa + INNER JOIN [rule].[splitAssignmentUnapproved] sp ON sp.splitAssignmentId = spa.splitAssignmentId + INNER JOIN [rule].[splitNameUnapproved] sn ON sp.splitNameId = sp.splitNameId + WHERE sn.conditionId = @conditionId + + + + -- handle split name + UPDATE sn + SET + sn.status = 'rejected' + FROM [rule].[splitNameUnapproved] sn + WHERE sn.conditionid = @conditionId + + + + -- handle split range + UPDATE sa + SET + sa.status = 'rejected' + FROM [rule].[splitRangeUnapproved] sa + JOIN [rule].[splitNameUnapproved] sna ON sa.splitNameId = sna.splitNameId + WHERE sna.conditionId = @conditionId + + + -- handle split assignment + UPDATE sa + SET + sa.status = 'rejected' + FROM [rule].[splitAssignmentUnapproved] sa + JOIN [rule].[splitNameUnapproved] sna ON sa.splitNameId = sna.splitNameId + WHERE sna.conditionId = @conditionId + + + + -- handle split range + UPDATE sr + SET + sa.status = 'rejected' + FROM [rule].[splitRangeUnapproved] sr + JOIN [rule].[splitNameUnapproved] sna ON sr.splitNameId = sna.splitNameId + WHERE sna.conditionId = @conditionId + + + COMMIT TRANSACTION + +END TRY +BEGIN CATCH + IF @@TRANCOUNT > 0 + ROLLBACK TRANSACTION + EXEC core.error + RETURN 55555 +END CATCH diff --git a/api/sql/schema/751-rule.alter.sql b/api/sql/schema/751-rule.alter.sql new file mode 100644 index 00000000..1714f6df --- /dev/null +++ b/api/sql/schema/751-rule.alter.sql @@ -0,0 +1,89 @@ +IF NOT EXISTS(SELECT 1 FROM sys.columns WHERE Name = N'status' AND OBJECT_ID = OBJECT_ID(N'rule.condition')) -- add column if it does not exist + BEGIN + ALTER TABLE [rule].[condition] + ADD status VARCHAR(20) NULL DEFAULT('pending') + + ALTER TABLE [rule].[condition] + WITH CHECK ADD CONSTRAINT [fk_condition_status] FOREIGN KEY ([status]) + REFERENCES [core].[status] ([statusId]) + END + +IF NOT EXISTS(SELECT 1 FROM sys.columns WHERE Name = N'status' AND OBJECT_ID = OBJECT_ID(N'rule.conditionActor')) -- add column if it does not exist + BEGIN + ALTER TABLE [rule].[conditionActor] + ADD status VARCHAR(20) NULL DEFAULT('pending') + + ALTER TABLE [rule].[conditionActor] + WITH CHECK ADD CONSTRAINT [fk_conditionActor_status] FOREIGN KEY ([status]) + REFERENCES [core].[status] ([statusId]) + END + +IF NOT EXISTS(SELECT 1 FROM sys.columns WHERE Name = N'status' AND OBJECT_ID = OBJECT_ID(N'rule.conditionItem')) -- add column if it does not exist + BEGIN + ALTER TABLE [rule].[conditionItem] + ADD status VARCHAR(20) NULL DEFAULT('pending') + + ALTER TABLE [rule].[conditionItem] + WITH CHECK ADD CONSTRAINT [fk_conditionItem_status] FOREIGN KEY ([status]) + REFERENCES [core].[status] ([statusId]) + END + +IF NOT EXISTS(SELECT 1 FROM sys.columns WHERE Name = N'status' AND OBJECT_ID = OBJECT_ID(N'rule.conditionProperty')) -- add column if it does not exist + BEGIN + ALTER TABLE [rule].[conditionProperty] + ADD status VARCHAR(20) NULL DEFAULT('pending') + + ALTER TABLE [rule].[conditionProperty] + WITH CHECK ADD CONSTRAINT [fk_conditionProperty_status] FOREIGN KEY ([status]) + REFERENCES [core].[status] ([statusId]) + END + +IF NOT EXISTS(SELECT 1 FROM sys.columns WHERE Name = N'status' AND OBJECT_ID = OBJECT_ID(N'rule.limit')) -- add column if it does not exist + BEGIN + ALTER TABLE [rule].[limit] + ADD status VARCHAR(20) NULL DEFAULT('pending') + + ALTER TABLE [rule].[limit] + WITH CHECK ADD CONSTRAINT [fk_limit_status] FOREIGN KEY ([status]) + REFERENCES [core].[status] ([statusId]) + END + +IF NOT EXISTS(SELECT 1 FROM sys.columns WHERE Name = N'status' AND OBJECT_ID = OBJECT_ID(N'rule.splitName')) -- add column if it does not exist + BEGIN + ALTER TABLE [rule].[splitName] + ADD status VARCHAR(20) NULL DEFAULT('pending') + + ALTER TABLE [rule].[splitName] + WITH CHECK ADD CONSTRAINT [fk_splitName_status] FOREIGN KEY ([status]) + REFERENCES [core].[status] ([statusId]) + END + +IF NOT EXISTS(SELECT 1 FROM sys.columns WHERE Name = N'status' AND OBJECT_ID = OBJECT_ID(N'rule.splitAssignment')) -- add column if it does not exist + BEGIN + ALTER TABLE [rule].[splitAssignment] + ADD status VARCHAR(20) NULL DEFAULT('pending') + + ALTER TABLE [rule].[splitAssignment] + WITH CHECK ADD CONSTRAINT [fk_splitAssignment_status] FOREIGN KEY ([status]) + REFERENCES [core].[status] ([statusId]) + END + +IF NOT EXISTS(SELECT 1 FROM sys.columns WHERE Name = N'status' AND OBJECT_ID = OBJECT_ID(N'rule.splitRange')) -- add column if it does not exist + BEGIN + ALTER TABLE [rule].[splitRange] + ADD status VARCHAR(20) NULL DEFAULT('pending') + + ALTER TABLE [rule].[splitRange] + WITH CHECK ADD CONSTRAINT [fk_splitRange_status] FOREIGN KEY ([status]) + REFERENCES [core].[status] ([statusId]) + END + +IF NOT EXISTS(SELECT 1 FROM sys.columns WHERE Name = N'status' AND OBJECT_ID = OBJECT_ID(N'rule.splitAnalytic')) -- add column if it does not exist + BEGIN + ALTER TABLE [rule].[splitAnalytic] + ADD status VARCHAR(20) NULL DEFAULT('pending') + + ALTER TABLE [rule].[splitAnalytic] + WITH CHECK ADD CONSTRAINT [fk_splitAnalytic_status] FOREIGN KEY ([status]) + REFERENCES [core].[status] ([statusId]) + END diff --git a/package.json b/package.json index 5baef6eb..d26fb425 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "ut-port-script": "^7.2.0", "ut-portal": "^8.0.3", "ut-run": "^10.64.7", - "ut-tools": "^6.40.2" + "ut-tools": "^6.41.1" }, "peerDependencies": { "classnames": "^2.2.6", @@ -44,6 +44,7 @@ "description": "UT Rule", "scripts": { "lint": "ut-lint .", + "lint-fix": "ut-lint . --fix", "release": "ut-release", "storybook": "ut-portal storybook -p 6006 --ci", "portal": "ut-portal", diff --git a/portal/index.stories.old.js b/portal/index.stories.old.js index 7fd17932..2ce63fdd 100644 --- a/portal/index.stories.old.js +++ b/portal/index.stories.old.js @@ -52,6 +52,17 @@ const page = app({ splitAnalytic: [], pagination: [] }), + 'rule.rule.addUnapproved': () => ({ + condition: [], + conditionActor: [], + conditionItem: [], + conditionProperty: [], + splitName: [], + splitRange: [], + splitAssignment: [], + limit: [], + splitAnalytic: [] + }), 'rule.rule.fetchDeleted': () => ({ condition: [], pagination: [] diff --git a/ui/react/components/Grid/index.js b/ui/react/components/Grid/index.js index 40835ac0..77e9704a 100644 --- a/ui/react/components/Grid/index.js +++ b/ui/react/components/Grid/index.js @@ -1,12 +1,13 @@ import PropTypes from 'prop-types'; import React from 'react'; -import {fromJS} from 'immutable'; -import {SimpleGrid} from 'ut-front-react/components/SimpleGrid'; +import { fromJS } from 'immutable'; +import { SimpleGrid } from 'ut-front-react/components/SimpleGrid'; import { updateGridColumnStorage, prepareGridFields } from 'ut-front-react/components/GridMenu/helpers'; import Text from 'ut-front-react/components/Text'; import style from './style.css'; import { Link } from 'react-router-dom'; + const propInStorage = 'rule_grid_fields'; export default class Grid extends React.Component { @@ -22,13 +23,17 @@ export default class Grid extends React.Component { state = { expandedGridColumns: [], columns: this.props.columns, - fields: prepareGridFields(propInStorage, [ - {title: this.props.columns.priority.title, name: 'priority'}, - {title: this.props.columns.channel.title, name: 'channel'}, - {title: this.props.columns.operation.title, name: 'operation'}, - {title: this.props.columns.source.title, name: 'source'}, - {title: this.props.columns.destination.title, name: 'destination'}, - {title: this.props.columns.limit.title, name: 'limit'}, + fields: this.prepareFields() + }; + + prepareFields() { + const fields = prepareGridFields(propInStorage, [ + { title: this.props.columns.priority.title, name: 'priority' }, + { title: this.props.columns.channel.title, name: 'channel' }, + { title: this.props.columns.operation.title, name: 'operation' }, + { title: this.props.columns.source.title, name: 'source' }, + { title: this.props.columns.destination.title, name: 'destination' }, + { title: this.props.columns.limit.title, name: 'limit' }, { title: 'Expansion', name: 'expansion' @@ -36,8 +41,14 @@ export default class Grid extends React.Component { ].map(f => { f.key = f.name; return f; - })) - }; + })); + + const findStatus = fields.filter(item => item.name === 'status'); + if (findStatus.length === 0) { + fields.splice(2, 0, { title: this.props.columns.status.title, name: 'status' }); // insert column to the 3rd position + } + return fields; + } handleGridExpansion = (id) => { const expandedGridColumns = this.state.expandedGridColumns; @@ -47,7 +58,7 @@ export default class Grid extends React.Component { } else { expandedGridColumns.push(id); } - this.setState({expandedGridColumns}); + this.setState({ expandedGridColumns }); }; renderGridColumn = (condition, keysToInclude, row, column) => { @@ -55,6 +66,7 @@ export default class Grid extends React.Component { for (const keyToInclude of keysToInclude) { if (Array.isArray(condition[keyToInclude])) { for (const index in condition[keyToInclude]) { + // console.log('conditionssss', condition); const record = condition[keyToInclude][index]; if (index > 4 && !this.state.expandedGridColumns.some(v => v === row.priority)) break; result.push(
@@ -84,13 +96,27 @@ export default class Grid extends React.Component {
); } - if (row.priority && column === 'priority') { + if (row.priority && column === 'priority' && row.status === 'approved') { result.push(
{row.priority}
); + } else { + result.push( +
+ {row.priority} +
+ ); } + if (row.status && column === 'status') { + result.push( +
+ {row.status} +
+ ); + } + return (
{result} @@ -120,7 +146,7 @@ export default class Grid extends React.Component { }); col.visible = col.visible === false ? !0 : !1; updateGridColumnStorage(propInStorage, col); - this.setState({fields: newFields}); + this.setState({ fields: newFields }); } }; @@ -134,6 +160,7 @@ export default class Grid extends React.Component { destinationAccountId: condition.destinationAccountId, operationEndDate: condition.operationEndDate, operationStartDate: condition.operationStartDate, + status: condition.status, priority: columns.priority.visible && condition.priority, channel: columns.channel.visible && this.props.formatedGridData[conditionId], operation: columns.operation.visible && this.props.formatedGridData[conditionId], @@ -148,6 +175,7 @@ export default class Grid extends React.Component { }; transformCellValue = (value, header, row, isHeader) => { + // console.log('new value', value); if (isHeader) { return value; } else { @@ -183,6 +211,7 @@ export default class Grid extends React.Component { const data = fromJS(this.getData()).sort((a, b) => { return a.get('priority') - b.get('priority'); }).toJS(); + // console.log('fields', data); return ( 0) { + // const user = currentValues.getIn(['person']); + // const id = user.get('actorId'); + // const pathname = getLink('ut-user:userValidate', { id }); + // const newTitle = baseTabTitle + // this.props.updateTabTitle(pathname, newTitle); + // this.setState({ + // updatedTitle: true + // }); + // } + } + + handleApproval() { + const conditionId = this.props.match.params.id; + const { canApprove } = this.permissions; + if (canApprove) { + this.props.approveRule({ conditionId: conditionId }); + this.props.removeTab(this.props.activeTab.pathname); + this.props.closeConfirmDialog(); + } + } + + handleRejection() { + const cd = this.props.confirmDialog.toJS(); + const conditionId = this.props.match.params.id; + const { canReject } = this.permissions; + if (canReject) { + this.props.rejectRuleChanges(conditionId, cd.value); + this.props.closeConfirmDialog(); + this.props.removeTab(this.props.activeTab.pathname); + } + } + + handleDialogOpen(config) { + return () => this.props.openConfirmDialog(config); + } + + handleDiscard(conditionId) { + const { canDiscard } = this.permissions; + if (canDiscard) { + return () => { + this.props.discardRuleChanges(conditionId); + this.props.closeConfirmDialog(); + this.props.removeTab(this.props.activeTab.pathname); + }; + } + } + + handleClose() { + this.props.removeTab(this.props.activeTab.pathname); + } + + getButtons() { + const { canApprove, canEdit } = this.permissions; + const { currentValues, newValues } = this.props; + const conditionId = newValues.getIn(['condition', 'conditionId']); + const isRejected = newValues.getIn(['condition', 'status']) === 'rejected'; + const isDeleted = newValues.getIn(['condition', 'isDeleted']); + const isLocked = !currentValues.getIn(['condition', 'isEnabled']); + const approveDialogConfig = { + isOpen: true, + showInput: false, + message: messages.approve, + buttons: [ + { label: 'Confirm', onClick: this.handleApproval }, + { label: 'Cancel', onClick: this.props.closeConfirmDialog } + ] + }; + const rejectReasonDialogConfig = { + isOpen: true, + showInput: true, + title: 'enter reject reason', + message: '', + buttons: [ + { label: 'Submit', onClick: this.handleRejection, disabled: !this.props.canSubmit }, + { label: 'Cancel', onClick: this.props.closeConfirmDialog } + ] + }; + const rejectDialogConfig = { + isOpen: true, + title: 'confirm rejection', + message: messages.reject, + showInput: false, + canSubmit: true, + buttons: [ + { label: 'Reject', onClick: this.handleDialogOpen(rejectReasonDialogConfig) }, + { label: 'Cancel', onClick: this.props.closeConfirmDialog } + ] + }; + + const discardChangesDialogConfig = { + isOpen: true, + title: 'DISCARD CHANGES MADE', + message: messages.discard, + showInput: false, + canSubmit: true, + buttons: [ + { label: 'Discard', onClick: this.handleDiscard(conditionId) }, + { label: 'Cancel', onClick: this.props.closeConfirmDialog } + ] + }; + + const buttonsMaker = [ + { + text: 'Discard changes', + onClick: this.handleDialogOpen(discardChangesDialogConfig) + }, + { + text: 'Cancel', + onClick: this.handleClose + } + ]; + + if (!isDeleted || !isLocked) { + buttonsMaker.unshift({ + text: 'Edit', + href: getLink('ut-rule:edit', { id: conditionId }) + }); + } + + const buttonsCheker = [ + { + text: 'Approve', + onClick: this.handleDialogOpen(approveDialogConfig) + }, + { + text: 'Reject', + onClick: this.handleDialogOpen(rejectDialogConfig) + }, + { + text: 'Close', + onClick: this.handleClose + } + ]; + if (canApprove && !isRejected) { + return buttonsCheker; + } else if (canEdit && isRejected) { + return buttonsMaker; + } else { + return [ + { + text: 'Cancel', + href: getLink('ut-rule:rules') + } + ]; + } + } + + getMakerCheckerValues() { + let { currentValues, newValues } = this.props; + // console.log('this.props current', currentValues.toJS()); + // console.log('this.props new', newValues.toJS()); + const isNew = currentValues.getIn(['condition', 'isNew']); + const isDeleted = newValues.getIn(['condition', 'isDeleted']); + const isRejected = currentValues.getIn(['condition', 'status']) === 'rejected'; + + if (isNew) { + newValues = currentValues; + } + if (isDeleted || isRejected) { + newValues = currentValues; + } + + const options = { isNew, isDeleted }; + return immutable.fromJS([ + mapGeneralInfoData(currentValues, newValues, options), + operationInfoData(currentValues, newValues, options), + sourceInfoData(currentValues, newValues, options), + destinationInfoData(currentValues, newValues, options), + ...splitCheckers.map(item => splitInfoData(currentValues, newValues, options, item.title, item.key)) + ]).filter(result => result); + } + + render() { + const { id, newValues, location, confirmDialog, value, errors, canSubmit, updateErrors, changeConfirmDialogValue } = this.props; + + const rejectReason = newValues.getIn(['condition', 'rejectReason']); + const isNew = newValues.getIn(['condition', 'isNew']) === 1; + const isDeleted = newValues.getIn(['condition', 'isDeleted']); + const isRejected = newValues.getIn(['condition', 'status']) === 'rejected'; + const compareGridStaticStrings = { + headingIsNew: 'New Rule', + headingWillBeDeleted: 'User will be deleted' + }; + + const pathname = getLink('ut-rule:validate', { id }); + // const rule = currentValues.condition || newValues.condition + + const title = confirmDialog.get('title'); + const buttons = confirmDialog.get('buttons'); + const isOpen = confirmDialog.get('isOpen'); + const showInput = confirmDialog.get('showInput'); + const message = confirmDialog.get('message'); + + return ( + + + + } + > + + + + + + + + + ); + } +} + +RuleApprove.contextTypes = { + checkPermission: PropTypes.func +}; + +RuleApprove.propTypes = { + // actions + getSingleRule: PropTypes.func, + setActiveTab: PropTypes.func, + changeConfirmDialogValue: PropTypes.func, + openConfirmDialog: PropTypes.func, + closeConfirmDialog: PropTypes.func, + removeTab: PropTypes.func, + updateErrors: PropTypes.func, + approveRule: PropTypes.func, + rejectRuleChanges: PropTypes.func, + updateTabTitle: PropTypes.func, + discardRuleChanges: PropTypes.func, + // data + location: PropTypes.object.isRequired, + match: PropTypes.object.isRequired, + id: PropTypes.any, + newValues: PropTypes.object, + value: PropTypes.string, + activeTab: PropTypes.object, + activeTabData: PropTypes.any, + currentValues: PropTypes.object, + confirmDialog: PropTypes.object, + languages: PropTypes.object, + canSubmit: PropTypes.bool, + errors: PropTypes.object + +}; + +const mapStateToProps = (state, ownProps) => { + // console.log('state in rule approve', state.ruleProfileReducer.toJS()); + // console.log('state in rule state', state); + const tab = state.ruleProfileReducer.getIn(['approve', ownProps.match.params.id]) || immutable.fromJS(defaultState); + + const currentValues = immutable.fromJS({ + condition: tab.getIn(['localData', 'condition']), + conditionActor: tab.getIn(['localData', 'conditionActor']), + conditionProperty: tab.getIn(['localData', 'conditionProperty']), + conditionItem: tab.getIn(['localData', 'conditionItem']), + limit: tab.getIn(['localData', 'limit']), + splitName: tab.getIn(['localData', 'splitName']), + splitAssignment: tab.getIn(['localData', 'splitAssignment']), + splitAnalytic: tab.getIn(['localData', 'splitAnalytic']), + splitRange: tab.getIn(['localData', 'splitRange']) + }); + + const newValues = immutable.fromJS({ + condition: tab.getIn(['localData', 'conditionUnapproved']), + conditionActor: tab.getIn(['localData', 'conditionActorUnapproved']), + conditionProperty: tab.getIn(['localData', 'conditionPropertyUnapproved']), + conditionItem: tab.getIn(['localData', 'conditionItemUnapproved']), + limit: tab.getIn(['localData', 'limitUnapproved']), + splitName: tab.getIn(['localData', 'splitNameUnapproved']), + splitAssignment: tab.getIn(['localData', 'splitAssignmentUnapproved']), + splitAnalytic: tab.getIn(['localData', 'splitAnalyticUnapproved']), + splitRange: tab.getIn(['localData', 'splitRangeUnapproved']) + }); + + // console.log('state currentvalues', currentValues.toJS()); + // console.log('state newvalues', newValues.toJS()); + + return { + id: ownProps.match.params.id, + currentValues, + newValues, + activeTab: state.tabMenu.active, + activeTabData: state.ruleProfileReducer.get('activeTab'), + confirmDialog: state.ruleProfileReducer.getIn(['common', 'confirmDialog']), + canSubmit: state.ruleProfileReducer.getIn(['common', 'confirmDialog', 'canSubmit']), + value: state.ruleProfileReducer.getIn(['common', 'confirmDialog', 'value']), + errors: tab.getIn(['errors']) || immutable.fromJS({}) + }; +}; + +export default connect( + mapStateToProps, + { + getSingleRule, + setActiveTab, + removeTab, + closeConfirmDialog, + openConfirmDialog, + changeConfirmDialogValue, + updateErrors, + approveRule, + rejectRuleChanges, + updateTabTitle, + discardRuleChanges + } +)(RuleApprove); diff --git a/ui/react/pages/RuleProfile/actionTypes.js b/ui/react/pages/RuleProfile/actionTypes.js index 234bbd7c..3e7696df 100644 --- a/ui/react/pages/RuleProfile/actionTypes.js +++ b/ui/react/pages/RuleProfile/actionTypes.js @@ -24,3 +24,13 @@ export const ADD_CUMULATIVE_RANGE = Symbol('ADD_CUMULATIVE_RANGE'); export const REMOVE_CUMULATIVE_RANGE = Symbol('REMOVE_CUMULATIVE_RANGE'); export const ADD_SPLIT = Symbol('ADD_SPLIT'); export const REMOVE_SPLIT = Symbol('REMOVE_SPLIT'); + +export const GET_SINGLE_RULE = Symbol('GET_SINGLE_RULE'); +export const SET_ACTIVE_TAB = Symbol('SET_ACTIVE_TAB'); +export const CLOSE_CONFIRM_DIALOG = Symbol('CLOSE_CONFIRM_DIALOG'); +export const OPEN_CONFIRM_DIALOG = Symbol('OPEN_CONFIRM_DIALOG'); +export const CHANGE_CONFIRM_DIALOG_VALUE = Symbol('CHANGE_CONFIRM_DIALOG_VALUE'); +export const UPDATE_USER_ERRORS = Symbol('UPDATE_USER_ERRORS'); +export const APPROVE_RULE = Symbol('APPROVE_RULE'); +export const REJECT_RULE = Symbol('REJECT_RULE'); +export const DISCARD_RULE = Symbol('DISCARD_RULE'); diff --git a/ui/react/pages/RuleProfile/actions.js b/ui/react/pages/RuleProfile/actions.js index 24dce24e..c50ccafe 100644 --- a/ui/react/pages/RuleProfile/actions.js +++ b/ui/react/pages/RuleProfile/actions.js @@ -15,28 +15,87 @@ export const getRule = (conditionId) => ({ export const createRule = (params) => ({ type: actionTypes.CREATE_RULE, - method: 'rule.rule.add', + method: 'rule.rule.addUnapproved', params: params || {} }); +export const closeConfirmDialog = () => ({ + type: actionTypes.CLOSE_CONFIRM_DIALOG +}); + +export function updateErrors(errors, id) { + return { + type: actionTypes.UPDATE_USER_ERRORS, + params: { + errors, + id + } + }; +} + +export const approveRule = (params) => ({ + type: actionTypes.APPROVE_RULE, + method: 'rule.rule.approve', + params +}); + +export const rejectRuleChanges = (conditionId, rejectReason) => ({ + type: actionTypes.REJECT_RULE, + method: 'rule.rule.reject', + params: { conditionId, rejectReason } +}); + +export function openConfirmDialog(config) { + return { + type: actionTypes.OPEN_CONFIRM_DIALOG, + params: { config } + }; +} + +export const discardRuleChanges = (conditionId) => ({ + type: actionTypes.DISCARD_RULE, + method: 'rule.rule.discard', + params: { conditionId } +}); + +export function changeConfirmDialogValue(value, canSubmit) { + return { + type: actionTypes.CHANGE_CONFIRM_DIALOG_VALUE, + params: { value, canSubmit } + }; +} + export const editRule = (params) => ({ type: actionTypes.EDIT_RULE, method: 'rule.rule.edit', params: params || {} }); +export const getSingleRule = (params) => ({ + type: actionTypes.GET_SINGLE_RULE, + method: 'rule.rule.get', + params +}); + +export function setActiveTab({ mode, id }) { + return { + type: actionTypes.SET_ACTIVE_TAB, + params: { mode, id } + }; +}; + export const resetRuleState = (params) => ({ type: actionTypes.RESET_RULE_STATE }); export const changeRuleProfile = (mode, id) => ({ type: actionTypes.CHANGE_RULE_PROFILE, - params: {mode, id} + params: { mode, id } }); export const changeActiveTab = (tab) => ({ type: actionTypes.CHANGE_ACTIVE_TAB, - params: {...tab} + params: { ...tab } }); // channel actions @@ -53,7 +112,7 @@ export const addProperty = (destinationProp) => ({ export const removeProperty = (propertyId, destinationProp) => ({ type: actionTypes.REMOVE_PROPERTY, - params: {propertyId}, + params: { propertyId }, destinationProp }); @@ -65,39 +124,39 @@ export const addLimit = () => { export const removeLimit = (limitId) => ({ type: actionTypes.REMOVE_LIMIT, - params: {limitId} + params: { limitId } }); export const addAssignment = (splitIndex) => ({ type: actionTypes.ADD_ASSIGNMENT, - params: {splitIndex} + params: { splitIndex } }); export const removeAssignment = (splitIndex, propertyId) => ({ type: actionTypes.REMOVE_ASSIGNMENT, - params: {splitIndex, propertyId} + params: { splitIndex, propertyId } }); export const addCumulative = (splitIndex) => { return { type: actionTypes.ADD_CUMULATIVE, - params: {splitIndex} + params: { splitIndex } }; }; export const removeCumulative = (splitIndex, cumulativeId) => ({ type: actionTypes.REMOVE_CUMULATIVE, - params: {splitIndex, cumulativeId} + params: { splitIndex, cumulativeId } }); export const addCumulativeRange = (splitIndex, cumulativeId) => ({ type: actionTypes.ADD_CUMULATIVE_RANGE, - params: {splitIndex, cumulativeId} + params: { splitIndex, cumulativeId } }); export const removeCumulativeRange = (splitIndex, cumulativeId, rangeId) => ({ type: actionTypes.REMOVE_CUMULATIVE_RANGE, - params: {splitIndex, cumulativeId, rangeId} + params: { splitIndex, cumulativeId, rangeId } }); export const addSplit = () => ({ @@ -106,10 +165,10 @@ export const addSplit = () => ({ export const removeSplit = (splitIndex) => ({ type: actionTypes.REMOVE_SPLIT, - params: {splitIndex} + params: { splitIndex } }); export const updateRuleErrors = (errors) => ({ type: actionTypes.UPDATE_RULE_ERRORS, - params: {errors} + params: { errors } }); diff --git a/ui/react/pages/RuleProfile/markerCheckerHelper.js b/ui/react/pages/RuleProfile/markerCheckerHelper.js new file mode 100644 index 00000000..3aa448c9 --- /dev/null +++ b/ui/react/pages/RuleProfile/markerCheckerHelper.js @@ -0,0 +1,182 @@ +import { compare } from 'ut-front-react/components/CompareGrid/helpers'; +import immutable from 'immutable'; + +export function capitalizeFirstLetter(str) { + try { + return str.charAt(0).toUpperCase() + str.slice(1); + } catch (error) { + return str; + } +} + +export function formatDate(dateString) { + if (dateString === undefined) { + return undefined; + } + const date = new Date(dateString); + return date.toUTCString(); +} + +const parseConditionItemData = (conditionItems, factor) => { + if (conditionItems === undefined) { + return immutable.fromJS([]); + } + return conditionItems.map(item => { + switch (factor) { + case item.get('factor'): + return { + key: capitalizeFirstLetter(item.get('itemTypeName')), + value: capitalizeFirstLetter(item.get('itemName')) + }; + default: + break; + } + }).filter(item => item !== undefined).toJS(); +}; + +const parseConditionActorData = (conditionActors, factor) => { + if (conditionActors === undefined) { + return immutable.fromJS([]); + } + return conditionActors.map(item => { + // console.log('currentOperationactors=====', item.toJS()); + switch (factor) { + case item.get('factor'): + return { + key: capitalizeFirstLetter(item.get('type')), + value: item.getIn(['actorId', 1]) // && item.get('actorId').length > 0 ? item.get('actorId')[0] : undefined + }; + default: + break; + } + }).filter(item => item !== undefined).toJS(); +}; + +const parseConditionPropertyData = (conditionProperty, factor) => { + if (conditionProperty === undefined) { + return immutable.fromJS([]); + } + return conditionProperty.map(item => { + switch (factor) { + case item.get('factor'): + return { + key: capitalizeFirstLetter(item.get('name')), + value: capitalizeFirstLetter(item.get('value')) + }; + default: + break; + } + }).filter(item => item !== undefined).toJS(); +}; + +const generalInfoMapper = (values) => { + // console.log('parsed state=================', parseConditionItemData(values.get('conditionItem'), 'cs')) + return immutable.fromJS([ + { + key: 'Priority', + value: values.getIn(['condition', 'priority']) + }, + { + key: 'Status', + value: capitalizeFirstLetter(values.getIn(['condition', 'status'])) + }, + ...parseConditionItemData(values.get('conditionItem'), 'cs'), + ...parseConditionPropertyData(values.get('conditionProperty'), 'co'), + ...parseConditionActorData(values.get('conditionActor'), 'co') + ].filter(item => item.value !== undefined)); +}; + +export function mapGeneralInfoData(currentValues, newValues, options) { + const generalInfoCurrent = generalInfoMapper(currentValues); + const generalInfoUnapproved = generalInfoMapper(newValues); + return compare('Channel')(generalInfoCurrent, generalInfoUnapproved, options); +} + +const operationItemDataMapper = (values) => { + // console.log('currentOperation============', values.toJS()) + return immutable.fromJS([ + ...parseConditionItemData(values.get('conditionItem'), 'oc'), + { + key: 'Operation Start Date', + value: formatDate(values.getIn(['condition', 'operationStartDate'])) + }, + { + key: 'Operation End Date', + value: formatDate(values.getIn(['condition', 'operationEndDate'])) + }, + ...parseConditionPropertyData(values.get('conditionProperty'), 'oc') + // ...cnditionItemStatusParser(values.get('conditionItem'), 'oc'), + ].filter(item => item.value !== undefined)); +}; + +export function operationInfoData(currentValues, newValues, options) { + const currentOperation = operationItemDataMapper(currentValues); + const newOperation = operationItemDataMapper(newValues); + return compare('Operation')(currentOperation, newOperation, options); +} + +const sourceDataMapper = (values) => { + return immutable.fromJS([ + ...parseConditionItemData(values.get('conditionItem'), 'ss'), + ...parseConditionItemData(values.get('conditionItem'), 'sc'), + ...parseConditionPropertyData(values.get('conditionProperty'), 'so'), + ...parseConditionActorData(values.get('conditionActor'), 'so') + ].filter(item => item.value !== undefined)); +}; + +export function sourceInfoData(currentValues, newValues, options) { + const currentSource = sourceDataMapper(currentValues); + const newSource = sourceDataMapper(newValues); + return compare('Source')(currentSource, newSource, options); +} + +const destinationDataMapper = (values) => { + return immutable.fromJS([ + ...parseConditionItemData(values.get('conditionItem'), 'ds'), + ...parseConditionItemData(values.get('conditionItem'), 'dc'), + ...parseConditionPropertyData(values.get('conditionProperty'), 'do'), + ...parseConditionActorData(values.get('conditionActor'), 'do') + ].filter(item => item.value !== undefined)); +}; + +export function destinationInfoData(currentValues, newValues, options) { + const currentDestination = destinationDataMapper(currentValues); + const newDestination = destinationDataMapper(newValues); + return compare('Destination')(currentDestination, newDestination, options); +} + +const seperateUpperCaseWords = (word) => { + try { + return capitalizeFirstLetter(word).match(/[A-Z][a-z]+|[0-9]+/g).join(' '); + } catch (error) { + if (word !== undefined) { + return capitalizeFirstLetter(word); + } + return word; + } +}; + +const splitDataMapper = (values, key) => { + if (values.has(key) && values.get(key) !== undefined && values.get(key).size > 0) { + const results = []; + values.get(key).map(split => { + // console.log('currentOperation============//', split.toJS()); + Object.keys(split.toJS()).forEach(key => { + results.push({ + key: seperateUpperCaseWords(key), + value: capitalizeFirstLetter(typeof (split.get(key)) === 'boolean' ? split.get(key).toString() : split.get(key)) + }); + }); + }); + // console.log('########', results); + return immutable.fromJS(results.filter(item => item.value !== null && !(item.key.includes('Id') || item.key.startsWith('id')))); + } + return immutable.fromJS([]); +}; + +export function splitInfoData(currentValues, newValues, options, title, key) { + // console.log('currentOperation============', newValues.toJS()); + const currentSplit = splitDataMapper(currentValues, key); + const newSplit = splitDataMapper(newValues, key); + return compare(title)(currentSplit, newSplit, options); +} diff --git a/ui/react/pages/RuleProfile/reducer.js b/ui/react/pages/RuleProfile/reducer.js index b2120b6f..618d9245 100644 --- a/ui/react/pages/RuleProfile/reducer.js +++ b/ui/react/pages/RuleProfile/reducer.js @@ -1,9 +1,32 @@ -import { fromJS } from 'immutable'; +import immutable, { fromJS } from 'immutable'; import * as actionTypes from './actionTypes'; import * as reducerHelper from './reducerHelper'; import { REMOVE_TAB } from 'ut-front-react/containers/TabMenu/actionTypes'; import { removeRules as DELETE_RULE } from '../Rules/actionTypes'; -const defaultState = { + +export const localDataObj = { + condition: {}, + conditionActor: [], + conditionProperty: [], + conditionItem: [], + limit: [], + splitName: [], + splitAssignment: [], + splitAnalytic: [], + splitRange: [] +}; + +export const confirmDialogObj = { + isOpen: false, + title: '', + value: '', + message: '', + showInput: false, + buttons: [], + canSubmit: true +}; + +export const defaultState = { nomenclatures: { accountProduct: [], cardProduct: [], @@ -21,12 +44,30 @@ const defaultState = { mode: null, id: null }, - rules: {} + rules: {}, + remoteData: {}, + localData: localDataObj, + errors: fromJS({}), + common: { + confirmDialog: confirmDialogObj + } }; export const ruleProfileReducer = (state = fromJS(defaultState), action) => { const options = state.get('config').toJS(); switch (action.type) { + case actionTypes.CLOSE_CONFIRM_DIALOG: + return reducerHelper.closeConfirmDialog(state, action, options); + case actionTypes.UPDATE_USER_ERRORS: + return reducerHelper.updateRuleErrors(state, action, options); + case actionTypes.CHANGE_CONFIRM_DIALOG_VALUE: + return reducerHelper.changeConfirmDialogValue(state, action, options); + case actionTypes.OPEN_CONFIRM_DIALOG: + return reducerHelper.openConfirmDialog(state, action, options); + case actionTypes.SET_ACTIVE_TAB: + return state.set('activeTab', immutable.fromJS(action.params)); + case actionTypes.GET_SINGLE_RULE: + return reducerHelper.getSingleRule(state, action, options); case actionTypes.CHANGE_RULE_PROFILE: return reducerHelper.changeRuleProfile(state, action, options); case actionTypes.FETCH_NOMENCLATURES: @@ -34,7 +75,10 @@ export const ruleProfileReducer = (state = fromJS(defaultState), action) => { case actionTypes.EDIT_RULE: case actionTypes.CREATE_RULE: return reducerHelper.saveRule(state, action, options); + case actionTypes.APPROVE_RULE: + return state; case actionTypes.GET_RULE: + case actionTypes.REJECT_RULE: return reducerHelper.getRule(state, action, options); case actionTypes.RESET_RULE_STATE: return reducerHelper.resetRuleProfile(state, action, options); diff --git a/ui/react/pages/RuleProfile/reducerHelper.js b/ui/react/pages/RuleProfile/reducerHelper.js index 17ecd3a6..064001b4 100644 --- a/ui/react/pages/RuleProfile/reducerHelper.js +++ b/ui/react/pages/RuleProfile/reducerHelper.js @@ -3,6 +3,7 @@ import { formatNomenclatures, prepareRuleModel } from './helpers'; import { fromJS } from 'immutable'; import { getLink } from 'ut-front-react/routerHelper'; import { defaultTabState, emptyLimit, emptySplit, emptyAssignment, emptyRange, defaultErrorState, emptyCumulative } from './Tabs/defaultState'; +import { confirmDialogObj } from './reducer'; const __placeholder__ = '__placeholder__'; export function changeRuleProfile(state, action, options) { @@ -14,7 +15,32 @@ export function changeRuleProfile(state, action, options) { return state; } +export function getSingleRule(state, action, options) { + if (action.methodRequestState === methodRequestState.FINISHED) { + const id = action.params.conditionId; + // console.log('response from action', action); + return state + .setIn(['approve', id, 'localData'], fromJS(action.result)); + } + return state; +} + +export const changeConfirmDialogValue = (state, action, options) => { + return state + .setIn(['common', 'confirmDialog', 'value'], action.params.value.value) + .setIn(['common', 'confirmDialog', 'canSubmit'], action.params.value.canSubmit); +}; + +export const closeConfirmDialog = (state, action, options) => { + return state.setIn(['common', 'confirmDialog'], fromJS(confirmDialogObj)); +}; + +export const openConfirmDialog = (state, action, options) => { + return state.setIn(['common', 'confirmDialog'], fromJS(action.params.config)); +}; + export function fetchNomenclatures(state, action, options) { + // console.log('fetched nomenclatures', action.result); if (action.methodRequestState === methodRequestState.FINISHED) { return state.set('nomenclatures', fromJS(formatNomenclatures(action.result.items))) .setIn(['config', 'nomenclaturesFetched'], true); @@ -91,7 +117,8 @@ export function changeActiveTab(state, action, options) { } // error update export function updateRuleErrors(state, action, options) { - const { mode, id } = options; + const mode = options.mode || state.getIn(['activeTab', 'mode']); + const id = options.id || state.getIn(['activeTab', 'id']); return state.setIn([mode, id, 'errors'], fromJS(action.params.errors)); } // common tab actions diff --git a/ui/react/pages/Rules/index.js b/ui/react/pages/Rules/index.js index e6d57d2e..6e87f884 100644 --- a/ui/react/pages/Rules/index.js +++ b/ui/react/pages/Rules/index.js @@ -40,7 +40,8 @@ class Main extends React.Component { selectedConditions: {}, canEdit: false, canDelete: false, - uiConfig: props.uiConfig.toJS() + uiConfig: props.uiConfig.toJS(), + selectedData: {} }; this.handleCheckboxSelect = this.handleCheckboxSelect.bind(this); @@ -50,10 +51,10 @@ class Main extends React.Component { } fetchData(props) { - const {pageSize, pageNumber} = props.pagination; + const { pageSize, pageNumber } = props.pagination; const showDeleted = props.showDeleted; - this.props.actions.fetchRules({pageSize, pageNumber}, showDeleted); + this.props.actions.fetchRules({ pageSize, pageNumber }, showDeleted); this.props.actions.fetchNomenclatures(this.state.uiConfig.nomenclatures); } @@ -72,7 +73,8 @@ class Main extends React.Component { selectedConditions: {}, canEdit: false, canDelete: false, - uiConfig: this.props.uiConfig.toJS() + uiConfig: this.props.uiConfig.toJS(), + selectedData: {} }; } @@ -81,6 +83,7 @@ class Main extends React.Component { } handleCheckboxSelect(isSelected, data) { + // console.log('selected', isSelected, 'data', data); const selectedConditions = this.state.selectedConditions; if (isSelected === null) { isSelected = selectedConditions[data.id]; @@ -94,7 +97,8 @@ class Main extends React.Component { this.setState({ selectedConditions: selectedConditions, canEdit: count === 1, - canDelete: count > 0 + canDelete: count > 0, + selectedData: !isSelected ? data : {} }); return !isSelected; } @@ -125,7 +129,7 @@ class Main extends React.Component { getHeaderButtons() { const buttons = []; this.context.checkPermission('rule.rule.add') && - buttons.push({text: 'Create Rule', href: getLink('ut-rule:create'), styleType: 'primaryLight'}); + buttons.push({ text: 'Create Rule', href: getLink('ut-rule:create'), styleType: 'primaryLight' }); return buttons; } @@ -136,22 +140,28 @@ class Main extends React.Component { const uiConfig = this.state.uiConfig; const columns = uiConfig.main.grid.columns; + // console.log('columns for grid', columns); const id = Object.keys(this.state.selectedConditions)[0]; + // console.log('this.state.selectedConditions', this.state.selectedData); + const selectedStatus = this.state.selectedData.status || ''; const showDeleted = this.props.showDeleted; const content = [ - {this.context.checkPermission('rule.rule.edit') && !showDeleted && - (
); } diff --git a/ui/react/pages/Rules/reducer.js b/ui/react/pages/Rules/reducer.js index 404fc2d4..1da8445c 100644 --- a/ui/react/pages/Rules/reducer.js +++ b/ui/react/pages/Rules/reducer.js @@ -36,6 +36,8 @@ export default (state = defaultState, action) => { showDeleted: showDeleted }); } + case actionTypes.lockUnlockRule: + return state; default: break; } diff --git a/validations/index.js b/validations/index.js index 74651fd3..f58d1f7b 100644 --- a/validations/index.js +++ b/validations/index.js @@ -16,6 +16,7 @@ module.exports = function validation() { require('./rule/rule.rule.get'), require('./rule/rule.rule.approve'), require('./rule/rule.rule.reject'), - require('./rule/rule.rule.discard') + require('./rule/rule.rule.discard'), + require('./rule/rule.rule.lock') ]; }; diff --git a/validations/rule/rule.rule.lock.js b/validations/rule/rule.rule.lock.js new file mode 100644 index 00000000..9c15f7ec --- /dev/null +++ b/validations/rule/rule.rule.lock.js @@ -0,0 +1,10 @@ +// @ts-check +/** @type { import("ut-run").validationFactory } */ +module.exports = ({ + joi +}) => ({ + 'rule.rule.lock': () => ({ + params: joi.any(), + result: joi.any() + }) +}); From 74f960baecf88b4b53415a5a0c9ce24809f5cb92 Mon Sep 17 00:00:00 2001 From: Raymond Date: Thu, 23 Jun 2022 07:27:01 +0000 Subject: [PATCH 5/5] code updates and improvements --- .../schema/750-rule.rule.addUnapproved.sql | 13 +++-- api/sql/schema/750-rule.rule.edit.sql | 42 +++++++------- api/sql/schema/750-rule.rule.fetch.sql | 38 ++++++++----- api/sql/schema/750-rule.rule.get.sql | 56 ++++++++++++------- ui/react/components/Grid/index.js | 2 +- ui/react/pages/RuleProfile/Approve/index.js | 2 +- ui/react/pages/RuleProfile/helpers.js | 2 +- ui/react/pages/Rules/index.js | 2 +- 8 files changed, 92 insertions(+), 65 deletions(-) diff --git a/api/sql/schema/750-rule.rule.addUnapproved.sql b/api/sql/schema/750-rule.rule.addUnapproved.sql index 034ef6ff..8896b392 100644 --- a/api/sql/schema/750-rule.rule.addUnapproved.sql +++ b/api/sql/schema/750-rule.rule.addUnapproved.sql @@ -41,14 +41,15 @@ BEGIN TRY destinationAccountId, createdOn, createdBy, - status) + status + ) SELECT [priority], operationStartDate, operationEndDate, sourceAccountId, destinationAccountId, - GETUTCDATE(), + GETDATE(), ISNULL(createdBy, @userId), 'pending' FROM @condition; @@ -99,7 +100,7 @@ BEGIN TRY 'pending' FROM @conditionProperty - INSERT INTO [rule].limitUnapproved ( + INSERT INTO [rule].limitUnapproved( conditionId, currency, minAmount, @@ -153,7 +154,7 @@ BEGIN TRY splitRange.x.value('(maxValue)[1]', 'money') AS maxValue, splitRange.x.value('(percent)[1]', 'money') AS [percent], splitRange.x.value('(percentBase)[1]', 'money') AS percentBase, - status + 'pending' AS status FROM @split.nodes('/data/rows/splitRange') AS splitRange(x) JOIN @@ -206,7 +207,7 @@ BEGIN TRY splitAssignment.x.value('(maxValue)[1]', 'money') AS maxValue, splitAssignment.x.value('(percent)[1]', 'decimal') AS [percent], splitAssignment.x.value('(description)[1]', 'VARCHAR(50)') AS description, - status + 'pending' AS status FROM @split.nodes('/data/rows/splitAssignment') AS splitAssignment(x) JOIN @@ -227,7 +228,7 @@ BEGIN TRY sn.splitAssignmentId AS splitAssignmentId, records.x.value('(name)[1]', 'NVARCHAR(50)') AS [name], records.x.value('(value)[1]', 'NVARCHAR(150)') AS [value], - status + 'pending' AS status FROM @split.nodes('/data/rows/splitAssignment/splitAnalytic') records(x) JOIN diff --git a/api/sql/schema/750-rule.rule.edit.sql b/api/sql/schema/750-rule.rule.edit.sql index e73c0122..5130bb09 100644 --- a/api/sql/schema/750-rule.rule.edit.sql +++ b/api/sql/schema/750-rule.rule.edit.sql @@ -10,7 +10,7 @@ AS SET NOCOUNT ON DECLARE @userId BIGINT = (SELECT [auth.actorId] FROM @meta) DECLARE @splitName TABLE (splitNameId INT, rowPosition INT) -DECLARE @splitAssignment [rule].splitAssignmentTT +DECLARE @splitAssignment [rule].splitAssignmentUnapprovedTT DECLARE @conditionId INT = (SELECT conditionId FROM @condition) BEGIN TRY @@ -18,7 +18,7 @@ BEGIN TRY IF EXISTS ( SELECT [priority] - FROM [rule].condition + FROM [rule].conditionUnapproved WHERE [priority] = (SELECT [priority] FROM @condition) AND conditionId != @conditionId AND isDeleted = 0 @@ -37,12 +37,12 @@ BEGIN TRY operationEndDate = DATEADD(ms, -3, DATEADD(dd, 1, DATEADD(dd, DATEDIFF(dd, 0, c1.operationEndDate), 0))), -- the last time on this date - 23:59:59.997 sourceAccountId = c1.sourceAccountId, destinationAccountId = c1.destinationAccountId, - updatedOn = GETUTCDATE(), + updatedOn = GETDATE(), updatedBy = @userId - FROM [rule].condition c + FROM [rule].conditionUnapproved c JOIN @condition c1 ON c.conditionId = c1.conditionId - MERGE INTO [rule].conditionActor ca + MERGE INTO [rule].conditionActorUnapproved ca USING @conditionActor ca1 ON ca.conditionId = ca1.conditionId AND ca.factor = ca1.factor AND ca.actorId = ca1.actorId WHEN NOT MATCHED BY TARGET THEN @@ -51,7 +51,7 @@ BEGIN TRY WHEN NOT MATCHED BY SOURCE AND ca.conditionId = @conditionId THEN DELETE; - MERGE INTO [rule].conditionItem ci + MERGE INTO [rule].conditionItemUnapproved ci USING @conditionItem ci1 ON ci.conditionId = ci1.conditionId AND ci.factor = ci1.factor AND ci.itemNameId = ci1.itemNameId WHEN NOT MATCHED BY TARGET THEN @@ -60,7 +60,7 @@ BEGIN TRY WHEN NOT MATCHED BY SOURCE AND ci.conditionId = @conditionId THEN DELETE; - MERGE INTO [rule].conditionProperty cp + MERGE INTO [rule].conditionPropertyUnapproved cp USING @conditionProperty cp1 ON cp.conditionId = cp1.conditionId AND cp.factor = cp1.factor AND cp.name = cp1.name WHEN MATCHED THEN @@ -72,7 +72,7 @@ BEGIN TRY WHEN NOT MATCHED BY SOURCE AND cp.conditionId = @conditionId THEN DELETE; - MERGE INTO [rule].limit l + MERGE INTO [rule].limitUnapproved l USING @limit l1 ON l.[limitId] = l1.limitId WHEN MATCHED THEN UPDATE @@ -94,25 +94,25 @@ BEGIN TRY DELETE; DELETE x - FROM [rule].splitRange x - JOIN [rule].splitName sn ON x.splitNameId = sn.splitNameId + FROM [rule].splitRangeUnapproved x + JOIN [rule].splitNameUnapproved sn ON x.splitNameId = sn.splitNameId LEFT JOIN @split.nodes('/data/rows/splitRange/splitRangeId') AS records(x) ON x.splitRangeId = records.x.value('(./text())[1]', 'INT') WHERE sn.conditionId = @conditionId AND records.x.value('(./text())[1]', 'INT') IS NULL DELETE x - FROM [rule].splitAnalytic x - JOIN [rule].splitAssignment sa ON x.splitAssignmentId = sa.splitAssignmentId - JOIN [rule].splitName sn ON sa.splitNameId = sn.splitNameId + FROM [rule].splitAnalyticUnapproved x + JOIN [rule].splitAssignmentUnapproved sa ON x.splitAssignmentId = sa.splitAssignmentId + JOIN [rule].splitNameUnapproved sn ON sa.splitNameId = sn.splitNameId LEFT JOIN @split.nodes('/data/rows/splitAssignment/splitAnalytic/splitAnalyticId') AS records(x) ON x.splitAnalyticId = records.x.value('(./text())[1]', 'INT') WHERE sn.conditionId = @conditionId AND records.x.value('(./text())[1]', 'INT') IS NULL DELETE x - FROM [rule].splitAssignment x - JOIN [rule].splitName sn ON x.splitNameId = sn.splitNameId + FROM [rule].splitAssignmentUnapproved x + JOIN [rule].splitNameUnapproved sn ON x.splitNameId = sn.splitNameId LEFT JOIN @split.nodes('/data/rows/splitAssignment/splitAssignmentId') AS records(x) ON x.splitAssignmentId = records.x.value('(./text())[1]', 'INT') WHERE sn.conditionId = @conditionId AND records.x.value('(./text())[1]', 'INT') IS NULL - MERGE INTO [rule].splitName x + MERGE INTO [rule].splitNameUnapproved x USING ( SELECT records.r.value('(./splitNameId)[1]', 'INT') AS splitNameId, @@ -132,7 +132,7 @@ BEGIN TRY DELETE OUTPUT INSERTED.splitNameId, sn.rowPos INTO @splitName; - MERGE INTO [rule].splitRange x + MERGE INTO [rule].splitRangeUnapproved x USING ( SELECT records.x.value('(./splitRangeId)[1]', 'INT') AS splitRangeId, @@ -200,7 +200,7 @@ BEGIN TRY r.[percent], r.percentBase); - MERGE INTO [rule].splitAssignment x + MERGE INTO [rule].splitAssignmentUnapproved x USING ( SELECT records.x.value('(./splitAssignmentId)[1]', 'INT') AS splitAssignmentId, @@ -227,7 +227,7 @@ BEGIN TRY VALUES (r.splitNameId, r.debit, r.credit, r.minValue, r.maxValue, r.[percent], r.description) OUTPUT INSERTED.* INTO @splitAssignment; - MERGE INTO [rule].splitAnalytic x + MERGE INTO [rule].splitAnalyticUnapproved x USING ( SELECT DISTINCT -- new splitAnalytic & new splitAssignment NULL AS [splitAnalyticId], @@ -288,7 +288,7 @@ BEGIN TRY SELECT @conditionId [key], c.priority rulePriority, - GETUTCDATE() editDateTime + GETDATE() editDateTime FROM @condition c FOR XML RAW @@ -297,7 +297,7 @@ BEGIN TRY EXEC core.outcome @proc = @@PROCID, @outcome = @outcome, @meta = @meta - EXEC [rule].[rule.fetch] @conditionId = @conditionId + EXEC [rule].[rule.fetch] @meta = @meta, @conditionId = @conditionId END TRY BEGIN CATCH IF @@TRANCOUNT > 0 diff --git a/api/sql/schema/750-rule.rule.fetch.sql b/api/sql/schema/750-rule.rule.fetch.sql index c50df35e..46252557 100644 --- a/api/sql/schema/750-rule.rule.fetch.sql +++ b/api/sql/schema/750-rule.rule.fetch.sql @@ -53,18 +53,27 @@ BEGIN AS ( SELECT rc.conditionId, - rc.[priority], - rc.operationEndDate, - rc.operationStartDate, - rc.sourceAccountId, - rc.destinationAccountId, - CASE WHEN rcu.status IS NOT NULL THEN rcu.status ELSE rc.status END AS status, - rc.isEnabled, - ROW_NUMBER() OVER(ORDER BY rc.[priority] ASC) AS rowNum, - COUNT(*) OVER(PARTITION BY 1) AS recordsTotal + rc.[priority], + rc.operationEndDate, + rc.operationStartDate, + rc.sourceAccountId, + rc.destinationAccountId, + rc.status, + rc.isEnabled, + ROW_NUMBER() OVER(ORDER BY rc.[priority] ASC) AS rowNum, + COUNT(*) OVER(PARTITION BY 1) AS recordsTotal FROM - [rule].condition rc - WHERE (@conditionId IS NULL OR rc.conditionId = @conditionId ) AND rc.isDeleted = 0) + ( + SELECT c.conditionId, c.status, c.[priority], c.operationStartDate, c.operationEndDate, c.sourceAccountId, c.destinationAccountId, 0 AS [isDeleted], c.isEnabled + FROM [rule].condition c + LEFT JOIN [rule].conditionUnapproved cu ON cu.conditionId = c.conditionId + UNION ALL + SELECT cu.conditionId, cu.status, cu.[priority], cu.operationStartDate, cu.operationEndDate, cu.sourceAccountId, cu.destinationAccountId, cu.isDeleted, cu.isEnabled + FROM [rule].conditionUnapproved cu + LEFT JOIN [rule].condition c ON c.conditionId = cu.conditionId + ) rc + WHERE (@conditionId IS NULL OR rc.conditionId = @conditionId ) AND rc.isDeleted = 0 + ) INSERT INTO #RuleConditions ( conditionId, [priority], operationEndDate, operationStartDate, sourceAccountId, destinationAccountId, rowNum, recordsTotal, status, isEnabled) @@ -102,7 +111,7 @@ BEGIN -- ca.*, a.actorType AS [type] FROM ( - SELECT ca.conditionId, ca.status, ca.factor, ca.actorId + SELECT ca.conditionId, ca.status, ca.factor, ca.actorId FROM [rule].conditionActor ca UNION ALL @@ -195,7 +204,7 @@ BEGIN sa.* FROM ( - SELECT * + SELECT * FROM [rule].splitAssignment UNION ALL @@ -212,7 +221,8 @@ BEGIN l.* FROM ( - SELECT * FROM [rule].limit + SELECT * + FROM [rule].limit UNION ALL diff --git a/api/sql/schema/750-rule.rule.get.sql b/api/sql/schema/750-rule.rule.get.sql index 72428464..1376eae5 100644 --- a/api/sql/schema/750-rule.rule.get.sql +++ b/api/sql/schema/750-rule.rule.get.sql @@ -38,7 +38,7 @@ BEGIN c.[operationStartDate], c.[sourceAccountId], c.[destinationAccountId], - c.status, + CASE WHEN co.status IS NOT NULL THEN co.status ELSE c.status END AS [status], CASE WHEN co.conditionId IS NULL THEN 1 ELSE 0 END AS [isNew], c.[isEnabled] FROM [rule].condition c @@ -66,39 +66,45 @@ BEGIN SELECT 'conditionActor' AS resultSetName SELECT - cca.conditionId, cca.factor, cca.actorId, cca.status, org.organizationName AS actorId, a.actorType AS [type] -- ca.*, a.actorType AS [type] + cca.conditionId, cca.factor, cca.actorId, CASE WHEN cau.status IS NOT NULL THEN cau.status ELSE cca.status END AS [status], org.organizationName AS actorId, a.actorType AS [type] + -- ca.*, a.actorType AS [type] FROM [rule].conditionActor cca - JOIN - core.actor a ON a.actorId = cca.actorId - JOIN - customer.organization org ON org.actorId = cca.actorId + JOIN + core.actor a ON a.actorId = cca.actorId + JOIN + customer.organization org ON org.actorId = cca.actorId + LEFT JOIN + [rule].conditionActorUnapproved cau ON cau.conditionId = cca.conditionId WHERE cca.conditionId = @conditionId SELECT 'conditionActorUnapproved' AS resultSetName SELECT - cca.conditionId, cca.factor, cca.actorId, cca.status, org.organizationName AS actorId, a.actorType AS [type] -- ca.*, a.actorType AS [type] + cca.conditionId, cca.factor, cca.actorId, cca.status, org.organizationName AS actorId, a.actorType AS [type] + -- ca.*, a.actorType AS [type] FROM [rule].conditionActorUnapproved cca - JOIN - core.actor a ON a.actorId = cca.actorId - JOIN - customer.organization org ON org.actorId = cca.actorId + JOIN + core.actor a ON a.actorId = cca.actorId + JOIN + customer.organization org ON org.actorId = cca.actorId WHERE cca.conditionId = @conditionId SELECT 'conditionItem' AS resultSetName SELECT - c.conditionId, c.factor, c.status, t.alias AS [type], t.name AS itemTypeName, i.itemName AS itemName + c.conditionId, c.factor, CASE WHEN ciu.status IS NOT NULL THEN ciu.status ELSE c.status END AS [status], t.alias AS [type], t.name AS itemTypeName, i.itemName AS itemName FROM [rule].conditionItem AS c JOIN core.itemName i ON i.itemNameId = c.itemNameId JOIN core.itemType t ON t.itemTypeId = i.itemTypeId + LEFT JOIN + [rule].conditionItemUnapproved ciu ON ciu.conditionId = c.conditionId WHERE c.conditionId = @conditionId SELECT 'conditionItemUnapproved' AS resultSetName SELECT c.conditionId, c.factor, c.status, t.alias AS [type], t.name AS itemTypeName, i.itemName AS itemName - FROM [rule].conditionItemUnapproved AS c + FROM [rule].conditionItemUnapproved AS c JOIN core.itemName i ON i.itemNameId = c.itemNameId JOIN core.itemType t ON t.itemTypeId = i.itemTypeId WHERE c.conditionId = @conditionId @@ -107,8 +113,9 @@ BEGIN SELECT 'conditionProperty' AS resultSetName SELECT - cp.* + cp.conditionId, cp.factor, cp.name, cp.value, CASE WHEN cpu.status IS NOT NULL THEN cpu.status ELSE cp.status END AS [status] FROM [rule].conditionProperty cp + LEFT JOIN [rule].conditionPropertyUnapproved cpu ON cpu.conditionId = cp.conditionId WHERE cp.conditionId = @conditionId @@ -123,8 +130,9 @@ BEGIN SELECT 'splitName' AS resultSetName SELECT - sn.* + sn.conditionId, sn.name, sn.splitNameId, sn.tag, CASE WHEN snu.status IS NOT NULL THEN snu.status ELSE sn.status END AS [status] FROM [rule].splitName sn + LEFT JOIN [rule].splitNameUnapproved snu ON snu.conditionId = sn.conditionId WHERE sn.conditionId = @conditionId SELECT 'splitNameUnapproved' AS resultSetName @@ -137,9 +145,13 @@ BEGIN SELECT 'splitRange' AS resultSetName SELECT - sr.* + sr.isSourceAmount, sr.maxValue, sr.minValue, sr.[percent], sr.percentBase, sr.splitNameId, sr.startAmount, sr.startAmountCurrency, + sr.startAmountDaily, sr.startAmountMonthly, sr.startAmountWeekly, sr.startCountDaily, sr.startCountMonthly, sr.startCountWeekly, + CASE WHEN sru.status IS NOT NULL THEN sru.status ELSE sr.status END AS [status] FROM [rule].splitRange sr JOIN [rule].splitName sn ON sn.splitNameId = sr.splitNameId + LEFT JOIN [rule].splitNameUnapproved snu ON snu.conditionId = sn.conditionId + LEFT JOIN [rule].splitRangeUnapproved sru ON sru.splitNameId = snu.splitNameId WHERE sn.conditionId = @conditionId SELECT 'splitRangeUnapproved' AS resultSetName @@ -154,9 +166,10 @@ BEGIN SELECT 'splitAssignment' AS resultSetName SELECT - sa.* + sa.credit, sa.debit, sa.description, sa.maxValue, sa.minValue, sa.[percent], sa.splitAssignmentId, sa.splitNameId, CASE WHEN sau.status IS NOT NULL THEN sau.status ELSE sa.status END AS status FROM [rule].splitAssignment sa JOIN [rule].splitName sn ON sn.splitNameId = sa.splitNameId + LEFT JOIN [rule].splitAssignmentUnapproved sau ON sau.splitAssignmentId = sa.splitAssignmentId WHERE sn.conditionId = @conditionId SELECT 'splitAssignmentUnapproved' AS resultSetName @@ -171,8 +184,10 @@ BEGIN SELECT 'limit' AS resultSetName SELECT - l.* + l.conditionId, l.credentials, l.currency, l.limitId, l.maxAmount, l.maxAmountDaily, l.maxAmountMonthly, l.maxAmountWeekly, + l.maxCountDaily, l.maxCountMonthly, l.maxCountWeekly, l.minAmount, l.priority, CASE WHEN lu.status IS NOT NULL THEN lu.status ELSE l.status END AS [status] FROM [rule].limit l + LEFT JOIN [rule].limitUnapproved lu ON lu.limitId = l.limitId WHERE l.conditionId = @conditionId SELECT 'limitUnapproved' AS resultSetName @@ -186,10 +201,11 @@ BEGIN SELECT 'splitAnalytic' AS resultSetName SELECT - san.* + san.name, san.splitAnalyticId, san.splitAssignmentId, san.value, CASE WHEN sau.status IS NOT NULL THEN sau.status ELSE san.status END AS [status] FROM [rule].splitAnalytic san JOIN [rule].splitAssignment sa ON sa.splitAssignmentId = san.splitAssignmentId JOIN [rule].splitName sn ON sn.splitNameId = sa.splitNameId + LEFT JOIN [rule].splitAnalyticUnapproved sau ON sau.splitAnalyticId = san.splitAnalyticId WHERE sn.conditionId = @conditionId SELECT 'splitAnalyticUnapproved' AS resultSetName @@ -200,4 +216,4 @@ BEGIN JOIN [rule].splitNameUnapproved sn ON sn.splitNameId = sa.splitNameId WHERE sn.conditionId = @conditionId -END + END diff --git a/ui/react/components/Grid/index.js b/ui/react/components/Grid/index.js index 9d09741f..2913b5a9 100644 --- a/ui/react/components/Grid/index.js +++ b/ui/react/components/Grid/index.js @@ -101,7 +101,7 @@ export default class Grid extends React.Component { ); } - if (row.priority && column === 'priority' && row.status === 'approved') { + if (row.priority && column === 'priority' && row.status === 'approved' && row.isEnabled !== 'Locked') { result.push(
{row.priority} diff --git a/ui/react/pages/RuleProfile/Approve/index.js b/ui/react/pages/RuleProfile/Approve/index.js index b5d1b760..4500166d 100644 --- a/ui/react/pages/RuleProfile/Approve/index.js +++ b/ui/react/pages/RuleProfile/Approve/index.js @@ -238,7 +238,7 @@ class RuleApprove extends Component { let { currentValues, newValues } = this.props; // console.log('this.props current', currentValues.toJS()); // console.log('this.props new', newValues.toJS()); - const isNew = currentValues.getIn(['condition', 'isNew']); + const isNew = newValues.getIn(['condition', 'isNew']); const isDeleted = newValues.getIn(['condition', 'isDeleted']); const isRejected = currentValues.getIn(['condition', 'status']) === 'rejected'; diff --git a/ui/react/pages/RuleProfile/helpers.js b/ui/react/pages/RuleProfile/helpers.js index ff1a5ad1..3f893a79 100644 --- a/ui/react/pages/RuleProfile/helpers.js +++ b/ui/react/pages/RuleProfile/helpers.js @@ -72,7 +72,7 @@ export const prepareRuleToSave = (rule) => { priority: channel.priority, operationStartDate: operation.startDate || null, operationEndDate: operation.endDate || null, - sourceAccontId: null, + sourceAccountId: null, destinationAccountId: null }]; formattedRule.conditionActor = []; diff --git a/ui/react/pages/Rules/index.js b/ui/react/pages/Rules/index.js index c652b2a7..4aa3eaa9 100644 --- a/ui/react/pages/Rules/index.js +++ b/ui/react/pages/Rules/index.js @@ -164,7 +164,7 @@ class Main extends React.Component { const showDeleted = this.props.showDeleted; const content = [ - {this.context.checkPermission('rule.rule.edit') && !showDeleted && id && + {this.context.checkPermission('rule.rule.edit') && !showDeleted && id && selectedStatus === 'approved' && !isLocked && (