IDEMPIERE-5567 Support of UUID as Key (FHCA-4195) - ChangeLog - FKRules (#1852)

* IDEMPIERE-5567 Support of UUID as Key (FHCA-4195) - ChangeLog - FKRules

* - change warning by IllegalArgumentException
- change package visibility to protected

* - remove unnecessary code - the Model Cascade is calling the deleteModelCascade for children too

* - Implement SysConfig AD_CHANGELOG_SAVE_UUID
- reorganize MSysConfig (there were entries out of order)

* - Add index for performance on AD_ChangeLog.Record_UU

* - Enable change log for tables with multi-key (like _Trl or _Access)

* - Enable saving change log for AD_ClientInfo

* - when updating a record that doesn't have UUID - assign one
This commit is contained in:
Carlos Ruiz 2023-05-28 17:47:30 +02:00 committed by GitHub
parent 1ff182e605
commit 281333e8b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 744 additions and 151 deletions

View File

@ -0,0 +1,190 @@
-- IDEMPIERE-5567 Support of UUID - ChangeLog (FHCA-4195)
SELECT register_migration_script('202304151832_IDEMPIERE-5567.sql') FROM dual;
SET SQLBLANKLINES ON
SET DEFINE OFF
-- Apr 15, 2023, 6:32:28 PM CEST
INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,FKConstraintType,IsHtml) VALUES (215835,0,'Record UUID',580,'Record_UU',36,'N','N','N','N','N',0,'N',200240,0,0,'Y',TO_TIMESTAMP('2023-04-15 18:32:27','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-04-15 18:32:27','YYYY-MM-DD HH24:MI:SS'),100,203804,'N','N','D','N','N','N','Y','42c26432-ba61-4375-901b-5573a94b3ca3','Y',0,'N','N','N','N')
;
-- Apr 15, 2023, 6:32:30 PM CEST
ALTER TABLE AD_ChangeLog ADD Record_UU VARCHAR2(36 CHAR) DEFAULT NULL
;
-- Apr 15, 2023, 6:34:30 PM CEST
UPDATE AD_Column SET IsMandatory='N',Updated=TO_TIMESTAMP('2023-04-15 18:34:30','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=8817
;
-- Apr 15, 2023, 6:34:32 PM CEST
ALTER TABLE AD_ChangeLog MODIFY Record_ID NUMBER(10) DEFAULT NULL
;
-- Apr 15, 2023, 6:34:32 PM CEST
ALTER TABLE AD_ChangeLog MODIFY Record_ID NULL
;
-- Apr 15, 2023, 6:34:44 PM CEST
INSERT INTO AD_Field (AD_Field_ID,Name,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,ColumnSpan) VALUES (207619,'Record UUID',488,215835,'Y',36,190,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2023-04-15 18:34:43','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-04-15 18:34:43','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','863e5828-5d78-43d9-bfd6-ef0bd26c6980','Y',190,2)
;
-- Apr 15, 2023, 6:34:50 PM CEST
INSERT INTO AD_Field (AD_Field_ID,Name,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,ColumnSpan) VALUES (207620,'Record UUID',487,215835,'Y',36,190,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2023-04-15 18:34:50','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-04-15 18:34:50','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','dab3415a-c850-401f-8b9a-891e60e2999e','Y',190,2)
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET IsDisplayed='Y', SeqNo=100, XPosition=4,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=207619
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET IsDisplayed='Y', SeqNo=110, XPosition=1,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=6779
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=120,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=6774
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=130,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=10946
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=140,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=54397
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=150,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=6780
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=160,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=6773
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=170,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=12356
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=180,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=10948
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=190,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=10947
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=0,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=204473
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET IsDisplayed='Y', SeqNo=100, XPosition=4,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=207620
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET IsDisplayed='Y', SeqNo=110, XPosition=1,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=6769
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=120,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=6764
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=130,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=10949
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=140,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=54396
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=150,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=6770
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=160,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=6763
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=170,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=12357
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=180,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=10951
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=190,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=10950
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=0,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=204474
;
-- May 21, 2023, 4:07:46 PM CEST
UPDATE AD_Field SET DisplayLogic='@AD_Reference_ID@=19 | @AD_Reference_ID@=30 | @AD_Reference_ID@=18 | @AD_Reference_ID@=21 | @AD_Reference_ID@=25 | @AD_Reference_ID@=31 | @AD_Reference_ID@=35 | @AD_Reference_ID@=33 | @AD_Reference_ID@=32 | @AD_Reference_ID@=53370 | @AD_Reference_ID@=200233 | @AD_Reference_ID@=200234 | @AD_Reference_ID@=200235 | @AD_Reference_ID@=200202 | @AD_Reference_ID@=200240',Updated=TO_TIMESTAMP('2023-05-21 16:07:46','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=202519
;
-- May 21, 2023, 4:13:15 PM CEST
UPDATE AD_Val_Rule SET Code='(
AD_Ref_List.Value = ''D''
/* Cascade/SetNull/Forbid supported for all DB constraints */
OR (AD_Ref_List.Value IN (''C'',''S'',''N'') AND @AD_Reference_ID@ IN (18,19,21,25,30,31,32,33,35,53370,200233,200234,200235))
/* ModelCascade supported for Table/TableDir/Search/RecordID */
OR (AD_Ref_List.Value = ''M'' AND @AD_Reference_ID@ IN (18,19,30,200202,200240))
/* ModelSetNull/ModelForbid supported for RecordID */
OR (AD_Ref_List.Value IN (''T'',''O'') AND @AD_Reference_ID@ IN (200202,200240))
)',Updated=TO_TIMESTAMP('2023-05-21 16:13:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Val_Rule_ID=200064
;
-- May 21, 2023, 4:14:25 PM CEST
UPDATE AD_Column SET FieldLength=36, FKConstraintType='D',Updated=TO_TIMESTAMP('2023-05-21 16:14:25','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=215833
;
-- May 22, 2023, 5:37:16 PM CEST
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200228,0,0,TO_TIMESTAMP('2023-05-22 17:37:15','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2023-05-22 17:37:15','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','AD_CHANGELOG_SAVE_UUID','B','Save the AD_ChangeLog.Record_UU -> B | Just for UUID based tables , A | Always , U | just UUID not ID','D','S','32161230-22c9-43eb-a327-f3b4841eeace')
;
-- May 23, 2023, 5:17:25 PM CEST
INSERT INTO AD_TableIndex (AD_Client_ID,AD_Org_ID,AD_TableIndex_ID,AD_TableIndex_UU,Created,CreatedBy,EntityType,IsActive,Name,Updated,UpdatedBy,AD_Table_ID,IsCreateConstraint,IsUnique,Processing,IsKey) VALUES (0,0,201247,'d0ab3ee4-418c-42e9-acfe-618750685bcc',TO_TIMESTAMP('2023-05-23 17:17:24','YYYY-MM-DD HH24:MI:SS'),100,'D','Y','ad_changelog_record_uu',TO_TIMESTAMP('2023-05-23 17:17:24','YYYY-MM-DD HH24:MI:SS'),100,580,'N','N','N','N')
;
-- May 23, 2023, 5:17:48 PM CEST
INSERT INTO AD_IndexColumn (AD_Client_ID,AD_Org_ID,AD_IndexColumn_ID,AD_IndexColumn_UU,Created,CreatedBy,EntityType,IsActive,Updated,UpdatedBy,AD_Column_ID,AD_TableIndex_ID,SeqNo) VALUES (0,0,201686,'6ce73812-0b30-4145-a9c5-ab1c73d4c386',TO_TIMESTAMP('2023-05-23 17:17:47','YYYY-MM-DD HH24:MI:SS'),100,'D','Y',TO_TIMESTAMP('2023-05-23 17:17:47','YYYY-MM-DD HH24:MI:SS'),100,215835,201247,10)
;
-- May 23, 2023, 5:17:53 PM CEST
CREATE INDEX ad_changelog_record_uu ON AD_ChangeLog (Record_UU)
;
/*
SET SERVEROUTPUT on;
-- Set Record_UU for existing records
DECLARE
cmd varchar2(2000);
v_cnt numeric;
BEGIN
FOR r IN (
SELECT DISTINCT t.TableName, cl.AD_Table_ID
FROM AD_ChangeLog cl
JOIN AD_Table t ON (cl.AD_Table_ID=t.AD_Table_ID)
WHERE cl.Record_UU IS NULL
AND cl.Record_ID IS NOT NULL
AND cl.EventChangeLog!='D'
) LOOP
cmd := 'UPDATE AD_ChangeLog SET Record_UU=(SELECT '
|| r.TableName
|| '_UU FROM '
|| r.TableName
|| ' WHERE '
|| r.TableName
|| '_ID=AD_ChangeLog.Record_ID) WHERE AD_Table_ID='
|| r.AD_Table_ID
|| ' AND Record_ID IS NOT NULL AND Record_UU IS NULL AND EventChangeLog!=''D''';
EXECUTE IMMEDIATE cmd;
DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || ' AD_ChangeLog.Record_UU set in ' || r.TableName);
END LOOP;
END;
/
*/

View File

@ -0,0 +1,189 @@
-- IDEMPIERE-5567 Support of UUID - ChangeLog (FHCA-4195)
SELECT register_migration_script('202304151832_IDEMPIERE-5567.sql') FROM dual;
-- Apr 15, 2023, 6:32:28 PM CEST
INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,FKConstraintType,IsHtml) VALUES (215835,0,'Record UUID',580,'Record_UU',36,'N','N','N','N','N',0,'N',200240,0,0,'Y',TO_TIMESTAMP('2023-04-15 18:32:27','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-04-15 18:32:27','YYYY-MM-DD HH24:MI:SS'),100,203804,'N','N','D','N','N','N','Y','42c26432-ba61-4375-901b-5573a94b3ca3','Y',0,'N','N','N','N')
;
-- Apr 15, 2023, 6:32:30 PM CEST
ALTER TABLE AD_ChangeLog ADD COLUMN Record_UU VARCHAR(36) DEFAULT NULL
;
-- Apr 15, 2023, 6:34:30 PM CEST
UPDATE AD_Column SET IsMandatory='N',Updated=TO_TIMESTAMP('2023-04-15 18:34:30','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=8817
;
-- Apr 15, 2023, 6:34:32 PM CEST
INSERT INTO t_alter_column values('ad_changelog','Record_ID','NUMERIC(10)',null,'NULL')
;
-- Apr 15, 2023, 6:34:32 PM CEST
INSERT INTO t_alter_column values('ad_changelog','Record_ID',null,'NULL',null)
;
-- Apr 15, 2023, 6:34:44 PM CEST
INSERT INTO AD_Field (AD_Field_ID,Name,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,ColumnSpan) VALUES (207619,'Record UUID',488,215835,'Y',36,190,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2023-04-15 18:34:43','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-04-15 18:34:43','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','863e5828-5d78-43d9-bfd6-ef0bd26c6980','Y',190,2)
;
-- Apr 15, 2023, 6:34:50 PM CEST
INSERT INTO AD_Field (AD_Field_ID,Name,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,ColumnSpan) VALUES (207620,'Record UUID',487,215835,'Y',36,190,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2023-04-15 18:34:50','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-04-15 18:34:50','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','dab3415a-c850-401f-8b9a-891e60e2999e','Y',190,2)
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET IsDisplayed='Y', SeqNo=100, XPosition=4,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=207619
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET IsDisplayed='Y', SeqNo=110, XPosition=1,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=6779
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=120,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=6774
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=130,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=10946
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=140,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=54397
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=150,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=6780
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=160,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=6773
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=170,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=12356
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=180,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=10948
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=190,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=10947
;
-- Apr 15, 2023, 6:35:45 PM CEST
UPDATE AD_Field SET SeqNo=0,Updated=TO_TIMESTAMP('2023-04-15 18:35:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=204473
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET IsDisplayed='Y', SeqNo=100, XPosition=4,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=207620
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET IsDisplayed='Y', SeqNo=110, XPosition=1,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=6769
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=120,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=6764
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=130,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=10949
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=140,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=54396
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=150,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=6770
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=160,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=6763
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=170,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=12357
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=180,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=10951
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=190,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=10950
;
-- Apr 15, 2023, 6:35:59 PM CEST
UPDATE AD_Field SET SeqNo=0,Updated=TO_TIMESTAMP('2023-04-15 18:35:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=204474
;
-- May 21, 2023, 4:07:46 PM CEST
UPDATE AD_Field SET DisplayLogic='@AD_Reference_ID@=19 | @AD_Reference_ID@=30 | @AD_Reference_ID@=18 | @AD_Reference_ID@=21 | @AD_Reference_ID@=25 | @AD_Reference_ID@=31 | @AD_Reference_ID@=35 | @AD_Reference_ID@=33 | @AD_Reference_ID@=32 | @AD_Reference_ID@=53370 | @AD_Reference_ID@=200233 | @AD_Reference_ID@=200234 | @AD_Reference_ID@=200235 | @AD_Reference_ID@=200202 | @AD_Reference_ID@=200240',Updated=TO_TIMESTAMP('2023-05-21 16:07:46','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=202519
;
-- May 21, 2023, 4:13:15 PM CEST
UPDATE AD_Val_Rule SET Code='(
AD_Ref_List.Value = ''D''
/* Cascade/SetNull/Forbid supported for all DB constraints */
OR (AD_Ref_List.Value IN (''C'',''S'',''N'') AND @AD_Reference_ID@ IN (18,19,21,25,30,31,32,33,35,53370,200233,200234,200235))
/* ModelCascade supported for Table/TableDir/Search/RecordID */
OR (AD_Ref_List.Value = ''M'' AND @AD_Reference_ID@ IN (18,19,30,200202,200240))
/* ModelSetNull/ModelForbid supported for RecordID */
OR (AD_Ref_List.Value IN (''T'',''O'') AND @AD_Reference_ID@ IN (200202,200240))
)',Updated=TO_TIMESTAMP('2023-05-21 16:13:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Val_Rule_ID=200064
;
-- May 21, 2023, 4:14:25 PM CEST
UPDATE AD_Column SET FieldLength=36, FKConstraintType='D',Updated=TO_TIMESTAMP('2023-05-21 16:14:25','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=215833
;
-- May 22, 2023, 5:37:16 PM CEST
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200228,0,0,TO_TIMESTAMP('2023-05-22 17:37:15','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2023-05-22 17:37:15','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','AD_CHANGELOG_SAVE_UUID','B','Save the AD_ChangeLog.Record_UU -> B | Just for UUID based tables , A | Always , U | just UUID not ID','D','S','32161230-22c9-43eb-a327-f3b4841eeace')
;
-- May 23, 2023, 5:17:25 PM CEST
INSERT INTO AD_TableIndex (AD_Client_ID,AD_Org_ID,AD_TableIndex_ID,AD_TableIndex_UU,Created,CreatedBy,EntityType,IsActive,Name,Updated,UpdatedBy,AD_Table_ID,IsCreateConstraint,IsUnique,Processing,IsKey) VALUES (0,0,201247,'d0ab3ee4-418c-42e9-acfe-618750685bcc',TO_TIMESTAMP('2023-05-23 17:17:24','YYYY-MM-DD HH24:MI:SS'),100,'D','Y','ad_changelog_record_uu',TO_TIMESTAMP('2023-05-23 17:17:24','YYYY-MM-DD HH24:MI:SS'),100,580,'N','N','N','N')
;
-- May 23, 2023, 5:17:48 PM CEST
INSERT INTO AD_IndexColumn (AD_Client_ID,AD_Org_ID,AD_IndexColumn_ID,AD_IndexColumn_UU,Created,CreatedBy,EntityType,IsActive,Updated,UpdatedBy,AD_Column_ID,AD_TableIndex_ID,SeqNo) VALUES (0,0,201686,'6ce73812-0b30-4145-a9c5-ab1c73d4c386',TO_TIMESTAMP('2023-05-23 17:17:47','YYYY-MM-DD HH24:MI:SS'),100,'D','Y',TO_TIMESTAMP('2023-05-23 17:17:47','YYYY-MM-DD HH24:MI:SS'),100,215835,201247,10)
;
-- May 23, 2023, 5:17:53 PM CEST
CREATE INDEX ad_changelog_record_uu ON AD_ChangeLog (Record_UU)
;
/*
-- Set Record_UU for existing records
DO $$
DECLARE
cmd varchar(2000);
r record;
v_cnt numeric;
BEGIN
FOR r IN
SELECT DISTINCT t.TableName, cl.AD_Table_ID
FROM AD_ChangeLog cl
JOIN AD_Table t ON (cl.AD_Table_ID=t.AD_Table_ID)
WHERE cl.Record_UU IS NULL
AND cl.Record_ID IS NOT NULL
AND cl.EventChangeLog!='D'
LOOP
cmd := 'UPDATE AD_ChangeLog SET Record_UU=(SELECT '
|| r.TableName
|| '_UU FROM '
|| r.TableName
|| ' WHERE '
|| r.TableName
|| '_ID=AD_ChangeLog.Record_ID) WHERE AD_Table_ID='
|| r.AD_Table_ID
|| ' AND Record_ID IS NOT NULL AND Record_UU IS NULL AND EventChangeLog!=''D''';
EXECUTE cmd;
GET DIAGNOSTICS v_cnt = ROW_COUNT;
RAISE NOTICE '% AD_ChangeLog.Record_UU set in %', v_cnt, r.TableName;
END LOOP;
END;
$$
;
*/

View File

@ -113,7 +113,7 @@ public class GridTab implements DataStatusListener, Evaluatee, Serializable
/**
*
*/
private static final long serialVersionUID = 2604313946261586651L;
private static final long serialVersionUID = 4674027561845549215L;
public static final String DEFAULT_STATUS_MESSAGE = "NavigateOrUpdate";
@ -2437,6 +2437,16 @@ public class GridTab implements DataStatusListener, Evaluatee, Serializable
return m_mTable.getKeyID(m_currentRow);
} // getRecord_ID
/**
* Get Current Table UUID
* @return Record_UU
*/
public String getRecord_UU()
{
UUID uuid = m_mTable.getUUID(m_currentRow);
return (uuid == null ? null : uuid.toString());
} // getRecord_UU
/**
* Get Key ID of row
* @param row row number

View File

@ -236,6 +236,15 @@ public interface I_AD_ChangeLog
*/
public int getRecord_ID();
/** Column name Record_UU */
public static final String COLUMNNAME_Record_UU = "Record_UU";
/** Set Record UUID */
public void setRecord_UU (String Record_UU);
/** Get Record UUID */
public String getRecord_UU();
/** Column name Redo */
public static final String COLUMNNAME_Redo = "Redo";

View File

@ -25,6 +25,7 @@ import java.util.logging.Level;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Util;
/**
* Change Log Model
@ -37,7 +38,7 @@ public class MChangeLog extends X_AD_ChangeLog
/**
*
*/
private static final long serialVersionUID = 7262833610411402160L;
private static final long serialVersionUID = 3082084206319959526L;
/**
* Do we track changes for this table
@ -170,6 +171,33 @@ public class MChangeLog extends X_AD_ChangeLog
int AD_Table_ID, int AD_Column_ID, int Record_ID,
int AD_Client_ID, int AD_Org_ID,
Object OldValue, Object NewValue, String event)
{
this(ctx, AD_ChangeLog_ID, TrxName, AD_Session_ID,
AD_Table_ID, AD_Column_ID, Record_ID, null,
AD_Client_ID, AD_Org_ID,
OldValue, NewValue, event);
}
/**
* Full Constructor
* @param ctx context
* @param AD_ChangeLog_ID 0 for new change log
* @param TrxName transaction
* @param AD_Session_ID session
* @param AD_Table_ID table
* @param AD_Column_ID column
* @param Record_ID record
* @param Record_UU record UUID
* @param AD_Client_ID client
* @param AD_Org_ID org
* @param OldValue old
* @param NewValue new
*/
public MChangeLog (Properties ctx,
int AD_ChangeLog_ID, String TrxName, int AD_Session_ID,
int AD_Table_ID, int AD_Column_ID, int Record_ID, String Record_UU,
int AD_Client_ID, int AD_Org_ID,
Object OldValue, Object NewValue, String event)
{
this (ctx, 0, TrxName);
if (AD_ChangeLog_ID == 0)
@ -184,7 +212,16 @@ public class MChangeLog extends X_AD_ChangeLog
//
setAD_Table_ID (AD_Table_ID);
setAD_Column_ID (AD_Column_ID);
setRecord_ID (Record_ID);
String saveUUID = MSysConfig.getValue(MSysConfig.AD_CHANGELOG_SAVE_UUID, "B");
// B - just based UUID tables (default)
// A - always
// U - just UUID, not ID
if (Record_ID > 0 && (!"U".equals(saveUUID) || Util.isEmpty(Record_UU))) {
setRecord_ID (Record_ID);
}
if ("U".equals(saveUUID) || "A".equals(saveUUID) || ("B".equals(saveUUID) && (Record_ID <= 0 || MTable.get(AD_Table_ID).isUUIDKeyTable()))) {
setRecord_UU (Record_UU);
}
//
setClientOrg (AD_Client_ID, AD_Org_ID);
//

View File

@ -82,7 +82,7 @@ public final class MLookup extends Lookup implements Serializable
}
// Don't load Search or CreatedBy/UpdatedBy
if (m_info.DisplayType == DisplayType.Search
if (m_info.DisplayType == DisplayType.Search || m_info.DisplayType == DisplayType.SearchUU
|| m_info.IsCreadedUpdatedBy)
return;
// Don't load Parents/Keys

View File

@ -46,8 +46,7 @@ public class MSession extends X_AD_Session implements ImmutablePOSupport
/**
*
*/
private static final long serialVersionUID = 480745219310430126L;
private static final long serialVersionUID = -5836154187760734691L;
/**
* Get existing or create local session
@ -323,7 +322,7 @@ public class MSession extends X_AD_Session implements ImmutablePOSupport
Object OldValue, Object NewValue)
{
return changeLog(TrxName, AD_ChangeLog_ID, AD_Table_ID, AD_Column_ID,
Record_ID, AD_Client_ID, AD_Org_ID, OldValue, NewValue,
Record_ID, null, AD_Client_ID, AD_Org_ID, OldValue, NewValue,
(String) null);
} // changeLog
@ -345,6 +344,31 @@ public class MSession extends X_AD_Session implements ImmutablePOSupport
int AD_Table_ID, int AD_Column_ID, int Record_ID,
int AD_Client_ID, int AD_Org_ID,
Object OldValue, Object NewValue, String event)
{
return changeLog(TrxName, AD_ChangeLog_ID, AD_Table_ID, AD_Column_ID,
Record_ID, null, AD_Client_ID, AD_Org_ID, OldValue, NewValue,
(String) null);
}
/**
* Create Change Log only if table is logged
* @param TrxName transaction name
* @param AD_ChangeLog_ID 0 for new change log
* @param AD_Table_ID table
* @param AD_Column_ID column
* @param Record_ID record
* @param Record_UU record UUID
* @param AD_Client_ID client
* @param AD_Org_ID org
* @param OldValue old
* @param NewValue new
* @return saved change log or null
*/
public MChangeLog changeLog (
String TrxName, int AD_ChangeLog_ID,
int AD_Table_ID, int AD_Column_ID, int Record_ID, String Record_UU,
int AD_Client_ID, int AD_Org_ID,
Object OldValue, Object NewValue, String event)
{
// Null handling
if (OldValue == null && NewValue == null)
@ -372,7 +396,7 @@ public class MSession extends X_AD_Session implements ImmutablePOSupport
PO.setCrossTenantSafe();
MChangeLog cl = new MChangeLog(getCtx(),
AD_ChangeLog_ID, TrxName, getAD_Session_ID(),
AD_Table_ID, AD_Column_ID, Record_ID, AD_Client_ID, AD_Org_ID,
AD_Table_ID, AD_Column_ID, Record_ID, Record_UU, AD_Client_ID, AD_Org_ID,
OldValue, NewValue, event);
if (cl.save())
return cl;

View File

@ -44,9 +44,10 @@ public class MSysConfig extends X_AD_SysConfig
/**
*
*/
private static final long serialVersionUID = -1169550637760344445L;
private static final long serialVersionUID = 1700160594551368619L;
public static final String ADDRESS_VALIDATION = "ADDRESS_VALIDATION";
public static final String AD_CHANGELOG_SAVE_UUID = "AD_CHANGELOG_SAVE_UUID";
public static final String ADDRESS_VALIDATION = "ADDRESS_VALIDATION";
public static final String ALERT_SEND_ATTACHMENT_AS_XLS = "ALERT_SEND_ATTACHMENT_AS_XLS";
public static final String ALLOCATION_DESCRIPTION = "ALLOCATION_DESCRIPTION";
public static final String ALLOW_APPLY_PAYMENT_TO_CREDITMEMO = "ALLOW_APPLY_PAYMENT_TO_CREDITMEMO";
@ -77,7 +78,7 @@ public class MSysConfig extends X_AD_SysConfig
public static final String BACKGROUND_JOB_MAX_PER_CLIENT = "BACKGROUND_JOB_MAX_PER_CLIENT";
public static final String BACKGROUND_JOB_MAX_PER_USER = "BACKGROUND_JOB_MAX_PER_USER";
public static final String BANK_STATEMENT_POST_WITH_DATE_FROM_LINE = "BANK_STATEMENT_POST_WITH_DATE_FROM_LINE";
public static final String BPARTNER_QUICK_ENTRY_OPTIONAL_LOCATION_TABLES = "BPARTNER_QUICK_ENTRY_OPTIONAL_LOCATION_TABLES";
public static final String BPARTNER_QUICK_ENTRY_OPTIONAL_LOCATION_TABLES = "BPARTNER_QUICK_ENTRY_OPTIONAL_LOCATION_TABLES";
public static final String CALENDAR_ALTERNATE_TIMEZONE = "CALENDAR_ALTERNATE_TIMEZONE";
public static final String CASH_AS_PAYMENT = "CASH_AS_PAYMENT";
public static final String CHANGE_PASSWORD_MUST_DIFFER = "CHANGE_PASSWORD_MUST_DIFFER";
@ -85,11 +86,11 @@ public class MSysConfig extends X_AD_SysConfig
public static final String CHECK_CREDIT_ON_PREPAY_ORDER = "CHECK_CREDIT_ON_PREPAY_ORDER";
public static final String CLIENT_ACCOUNTING = "CLIENT_ACCOUNTING";
public static final String DASHBOARD_LAYOUT_ORIENTATION = "DASHBOARD_LAYOUT_ORIENTATION";
public static final String DB_READ_REPLICA_NORMAL_MAX_ITERATIONS = "DB_READ_REPLICA_NORMAL_MAX_ITERATIONS";
public static final String DB_READ_REPLICA_NORMAL_TIMEOUT_IN_MILLISECONDS = "DB_READ_REPLICA_NORMAL_TIMEOUT_IN_MILLISECONDS";
public static final String DB_READ_REPLICA_URLS = "DB_READ_REPLICA_URLS";
public static final String DEFAULT_COA_PATH = "DEFAULT_COA_PATH";
public static final String DEFAULT_ENTITYTYPE = "DEFAULT_ENTITYTYPE"; // used as default in entity type columns with get_sysconfig
public static final String DB_READ_REPLICA_NORMAL_MAX_ITERATIONS = "DB_READ_REPLICA_NORMAL_MAX_ITERATIONS";
public static final String DB_READ_REPLICA_NORMAL_TIMEOUT_IN_MILLISECONDS = "DB_READ_REPLICA_NORMAL_TIMEOUT_IN_MILLISECONDS";
public static final String DB_READ_REPLICA_URLS = "DB_READ_REPLICA_URLS";
public static final String DICTIONARY_ID_PASSWORD = "DICTIONARY_ID_PASSWORD";
public static final String DICTIONARY_ID_USE_CENTRALIZED_ID = "DICTIONARY_ID_USE_CENTRALIZED_ID";
public static final String DICTIONARY_ID_USER = "DICTIONARY_ID_USER";
@ -116,19 +117,19 @@ public class MSysConfig extends X_AD_SysConfig
public static final String IMAGE_DB_STORAGE_SAVE_AS_ZIP = "IMAGE_DB_STORAGE_SAVE_AS_ZIP";
public static final String INFO_DEFAULTSELECTED = "INFO_DEFAULTSELECTED";
public static final String INFO_DOUBLECLICKTOGGLESSELECTION = "INFO_DOUBLECLICKTOGGLESSELECTION";
public static final String INFO_PRODUCT_SHOW_PRODUCTS_WITHOUT_PRICE = "INFO_PRODUCT_SHOW_PRODUCTS_WITHOUT_PRICE";
public static final String INFO_PRODUCT_SHOW_PRODUCTS_WITHOUT_PRICE = "INFO_PRODUCT_SHOW_PRODUCTS_WITHOUT_PRICE";
public static final String Invoice_ReverseUseNewNumber = "Invoice_ReverseUseNewNumber";
public static final String JASPER_SWAP_MAX_PAGES = "JASPER_SWAP_MAX_PAGES";
public static final String LABEL_AUTOMATIC_COLOR = "LABEL_AUTOMATIC_COLOR";
public static final String LASTRUN_RECORD_COUNT = "LASTRUN_RECORD_COUNT";
public static final String LDAP_TYPE = "LDAP_TYPE";
public static final String LDAP_TYPE = "LDAP_TYPE";
public static final String LOCATION_MAPS_DESTINATION_ADDRESS = "LOCATION_MAPS_DESTINATION_ADDRESS";
public static final String LOCATION_MAPS_ROUTE_PREFIX = "LOCATION_MAPS_ROUTE_PREFIX";
public static final String LOCATION_MAPS_SOURCE_ADDRESS = "LOCATION_MAPS_SOURCE_ADDRESS";
public static final String LOCATION_MAPS_URL_PREFIX = "LOCATION_MAPS_URL_PREFIX";
public static final String LOCATION_MAX_CITY_ROWS = "LOCATION_MAX_CITY_ROWS";
public static final String LOGIN_HELP_URL = "LOGIN_HELP_URL";
public static final String LOGIN_PREFIX_SEPARATOR = "LOGIN_PREFIX_SEPARATOR";
public static final String LOGIN_PREFIX_SEPARATOR = "LOGIN_PREFIX_SEPARATOR";
public static final String LOGIN_SELECT_ROLE_HELP_URL = "LOGIN_SELECT_ROLE_HELP_URL";
public static final String LOGIN_SHOW_RESETPASSWORD = "LOGIN_SHOW_RESETPASSWORD";
public static final String LOGIN_WITH_TENANT_PREFIX = "LOGIN_WITH_TENANT_PREFIX";
@ -138,16 +139,16 @@ public class MSysConfig extends X_AD_SysConfig
public static final String MAIL_SEND_CREDENTIALS = "MAIL_SEND_CREDENTIALS";
public static final String MAX_ACTIVITIES_IN_LIST = "MAX_ACTIVITIES_IN_LIST";
public static final String MAX_RESULTS_PER_SEARCH_IN_DOCUMENT_CONTROLLER = "MAX_RESULTS_PER_SEARCH_IN_DOCUMENT_CONTROLLER";
public static final String MAX_ROWS_IN_TABLE_COMBOLIST = "MAX_ROWS_IN_TABLE_COMBOLIST";
public static final String MAX_ROWS_IN_TABLE_COMBOLIST = "MAX_ROWS_IN_TABLE_COMBOLIST";
public static final String MAX_TEXT_LENGTH_ON_GRID_VIEW = "MAX_TEXT_LENGTH_ON_GRID_VIEW";
public static final String MENU_INFOUPDATER_SLEEP_MS = "MENU_INFOUPDATER_SLEEP_MS";
public static final String MESSAGES_AT_TENANT_LEVEL = "MESSAGES_AT_TENANT_LEVEL";
public static final String MFA_NTP_TIMEOUT_IN_MILLISECONDS = "MFA_NTP_TIMEOUT_IN_MILLISECONDS";
public static final String MFA_REGISTERED_DEVICE_EXPIRATION_DAYS = "MFA_REGISTERED_DEVICE_EXPIRATION_DAYS";
public static final String MONITOR_INITIAL_WAIT_FOR_CLUSTER_IN_SECONDS = "MONITOR_INITIAL_WAIT_FOR_CLUSTER_IN_SECONDS";
public static final String MONITOR_MAX_WAIT_FOR_CLUSTER_IN_SECONDS = "MONITOR_MAX_WAIT_FOR_CLUSTER_IN_SECONDS";
public static final String MFA_REGISTERED_DEVICE_EXPIRATION_DAYS = "MFA_REGISTERED_DEVICE_EXPIRATION_DAYS";
public static final String MFG_ValidateCostsDifferenceOnCreate = "MFG_ValidateCostsDifferenceOnCreate";
public static final String MFG_ValidateCostsOnCreate = "MFG_ValidateCostsOnCreate";
public static final String MONITOR_INITIAL_WAIT_FOR_CLUSTER_IN_SECONDS = "MONITOR_INITIAL_WAIT_FOR_CLUSTER_IN_SECONDS";
public static final String MONITOR_MAX_WAIT_FOR_CLUSTER_IN_SECONDS = "MONITOR_MAX_WAIT_FOR_CLUSTER_IN_SECONDS";
public static final String MSEQUENCE_GETNEXT_TIMEOUT = "MSEQUENCE_GETNEXT_TIMEOUT";
public static final String PAYMENT_OVERWRITE_DOCUMENTNO_WITH_CHECK_ON_PAYMENT = "PAYMENT_OVERWRITE_DOCUMENTNO_WITH_CHECK_ON_PAYMENT";
public static final String PAYMENT_OVERWRITE_DOCUMENTNO_WITH_CHECK_ON_RECEIPT = "PAYMENT_OVERWRITE_DOCUMENTNO_WITH_CHECK_ON_RECEIPT";
@ -161,7 +162,7 @@ public class MSysConfig extends X_AD_SysConfig
public static final String PROJECT_ID_USE_CENTRALIZED_ID = "PROJECT_ID_USE_CENTRALIZED_ID";
public static final String PROJECT_ID_USER = "PROJECT_ID_USER";
public static final String PROJECT_ID_WEBSITE = "PROJECT_ID_WEBSITE";
public static final String QUICKFORM_PAGE_SIZE = "QUICKFORM_PAGE_SIZE";
public static final String QUICKFORM_PAGE_SIZE = "QUICKFORM_PAGE_SIZE";
public static final String REAL_TIME_POS = "REAL_TIME_POS";
public static final String RecentItems_MaxSaved = "RecentItems_MaxSaved";
public static final String RecentItems_MaxShown = "RecentItems_MaxShown";
@ -177,7 +178,7 @@ public class MSysConfig extends X_AD_SysConfig
public static final String TAX_LOOKUP_SERVICE="TAX_LOOKUP_SERVICE";
public static final String TOP_MARGIN_PIXELS_FOR_HEADER = "TOP_MARGIN_PIXELS_FOR_HEADER";
public static final String TRACE_ALL_TRX_CONNECTION_GET = "TRACE_ALL_TRX_CONNECTION_GET";
public static final String TRX_AUTOSET_DISPLAY_NAME = "TRX_AUTOSET_DISPLAY_NAME";
public static final String TRX_AUTOSET_DISPLAY_NAME = "TRX_AUTOSET_DISPLAY_NAME";
public static final String TWOPACK_COMMIT_DDL = "2PACK_COMMIT_DDL";
public static final String TWOPACK_HANDLE_TRANSLATIONS = "2PACK_HANDLE_TRANSLATIONS";
public static final String USE_EMAIL_FOR_LOGIN = "USE_EMAIL_FOR_LOGIN";
@ -242,8 +243,8 @@ public class MSysConfig extends X_AD_SysConfig
public static final String ZK_SEARCH_AUTO_COMPLETE_MAX_ROWS = "ZK_SEARCH_AUTO_COMPLETE_MAX_ROWS";
public static final String ZK_SEQ_DEFAULT_VALUE_PANEL = "ZK_SEQ_DEFAULT_VALUE_PANEL";
public static final String ZK_SESSION_TIMEOUT_IN_SECONDS = "ZK_SESSION_TIMEOUT_IN_SECONDS";
public static final String ZK_THEME_USE_FONT_ICON_FOR_IMAGE = "ZK_THEME_USE_FONT_ICON_FOR_IMAGE";
public static final String ZK_THEME = "ZK_THEME";
public static final String ZK_THEME_USE_FONT_ICON_FOR_IMAGE = "ZK_THEME_USE_FONT_ICON_FOR_IMAGE";
public static final String ZK_TOOLBAR_SHOW_MORE_VERTICAL = "ZK_TOOLBAR_SHOW_MORE_VERTICAL";
public static final String ZK_USE_PDF_JS_VIEWER = "ZK_USE_PDF_JS_VIEWER";
public static final String ZOOM_ACROSS_QUERY_TIMEOUT = "ZOOM_ACROSS_QUERY_TIMEOUT";

View File

@ -878,6 +878,7 @@ public class MTable extends X_AD_Table implements ImmutablePOSupport
return (tablename.equals("AD_Org") ||
tablename.equals("AD_OrgInfo") ||
tablename.equals("AD_Client") || // IDEMPIERE-668
tablename.equals("AD_ClientInfo") ||
tablename.equals("AD_AllClients_V") ||
tablename.equals("AD_ReportView") ||
tablename.equals("AD_Role") ||

View File

@ -2336,11 +2336,6 @@ public abstract class PO
*/
public boolean save()
{
checkImmutable();
checkValidContext();
checkCrossTenant(true);
checkRecordIDCrossTenant();
CLogger.resetLast();
boolean newRecord = is_new(); // save locally as load resets
if (!newRecord && !is_Changed())
@ -2349,6 +2344,12 @@ public abstract class PO
return true;
}
checkImmutable();
checkValidContext();
checkCrossTenant(true);
checkRecordIDCrossTenant();
checkRecordUUCrossTenant();
if (m_setErrorsFilled) {
for (int i = 0; i < m_setErrors.length; i++) {
ValueNamePair setError = m_setErrors[i];
@ -2830,6 +2831,18 @@ public abstract class PO
log.fine("No Session found");
int AD_ChangeLog_ID = 0;
//uuid secondary key - when updating, if the record doesn't have UUID, assign one
int uuidIndex = p_info.getColumnIndex(getUUIDColumnName());
if (uuidIndex >= 0)
{
String value = (String)get_Value(uuidIndex);
if (p_info.getColumn(uuidIndex).FieldLength == 36 && (value == null || value.length() == 0))
{
UUID uuid = UUID.randomUUID();
set_ValueNoCheck(p_info.getColumnName(uuidIndex), uuid.toString());
}
}
int size = get_ColumnCount();
for (int i = 0; i < size; i++)
{
@ -3009,7 +3022,6 @@ public abstract class PO
// Change Log - Only
if (session != null
&& m_IDs.length == 1
&& p_info.isAllowLogging(i) // logging allowed
&& !p_info.isEncrypted(i) // not encrypted
&& !p_info.isVirtualColumn(i) // no virtual column
@ -3026,7 +3038,7 @@ public abstract class PO
MChangeLog cLog = session.changeLog (
m_trxName, AD_ChangeLog_ID,
p_info.getAD_Table_ID(), p_info.getColumn(i).AD_Column_ID,
get_ID(), getAD_Client_ID(), getAD_Org_ID(), oldV, newV, MChangeLog.EVENTCHANGELOG_Update);
(m_IDs.length == 1 ? get_ID() : 0), get_UUID(), getAD_Client_ID(), getAD_Org_ID(), oldV, newV, MChangeLog.EVENTCHANGELOG_Update);
if (cLog != null)
AD_ChangeLog_ID = cLog.getAD_ChangeLog_ID();
}
@ -3355,29 +3367,33 @@ public abstract class PO
if (withValues && m_IDs.length == 1 && p_info.hasKeyColumn()
&& m_KeyColumns[0].endsWith("_ID") && !Env.isUseCentralizedId(p_info.getTableName()))
{
int id = DB.getSQLValueEx(get_TrxName(), "SELECT " + m_KeyColumns[0] + " FROM "
+ p_info.getTableName() + " WHERE " + getUUIDColumnName() + "=?", get_ValueAsString(getUUIDColumnName()));
StringBuilder sql = new StringBuilder("SELECT ").append(m_KeyColumns[0]).append(" FROM ").append(p_info.getTableName()).append(" WHERE ").append(getUUIDColumnName()).append("=?");
int id = DB.getSQLValueEx(get_TrxName(), sql.toString(), get_ValueAsString(getUUIDColumnName()));
m_IDs[0] = Integer.valueOf(id);
set_ValueNoCheck(m_KeyColumns[0], m_IDs[0]);
}
if (!Env.isUseCentralizedId(p_info.getTableName()))
{
int ki = p_info.getColumnIndex(m_KeyColumns[0]);
// Change Log - Only
String insertLog = MSysConfig.getValue(MSysConfig.SYSTEM_INSERT_CHANGELOG, "Y", getAD_Client_ID());
if ( session != null
&& m_IDs.length == 1
&& p_info.isAllowLogging(ki) // logging allowed
&& !p_info.isEncrypted(ki) // not encrypted
&& !p_info.isVirtualColumn(ki) // no virtual column
&& !"Password".equals(p_info.getColumnName(ki))
&& (insertLog.equalsIgnoreCase("Y")
|| (insertLog.equalsIgnoreCase("K") && p_info.getColumn(ki).IsKey))
)
&& ( insertLog.equalsIgnoreCase("Y")
|| ( insertLog.equalsIgnoreCase("K")
&& ( p_info.getColumn(ki).IsKey
|| p_info.getColumn(ki).ColumnName.equals(PO.getUUIDColumnName(p_info.getTableName()))))))
{
int id = (m_IDs.length == 1 ? get_ID() : 0);
// change log on new
MChangeLog cLog = session.changeLog (
m_trxName, AD_ChangeLog_ID,
p_info.getAD_Table_ID(), p_info.getColumn(ki).AD_Column_ID,
get_ID(), getAD_Client_ID(), getAD_Org_ID(), null, id, MChangeLog.EVENTCHANGELOG_Insert);
(m_IDs.length == 1 ? get_ID() : 0), get_UUID(), getAD_Client_ID(), getAD_Org_ID(), null, (id == 0 ? get_UUID() : id), MChangeLog.EVENTCHANGELOG_Insert);
if (cLog != null)
AD_ChangeLog_ID = cLog.getAD_ChangeLog_ID();
}
@ -3637,7 +3653,6 @@ public abstract class PO
// Change Log - Only
String insertLog = MSysConfig.getValue(MSysConfig.SYSTEM_INSERT_CHANGELOG, "Y", getAD_Client_ID());
if (!generateScriptOnly && session != null
&& m_IDs.length == 1
&& p_info.isAllowLogging(i) // logging allowed
&& !p_info.isEncrypted(i) // not encrypted
&& !p_info.isVirtualColumn(i) // no virtual column
@ -3650,7 +3665,7 @@ public abstract class PO
MChangeLog cLog = session.changeLog (
m_trxName, AD_ChangeLog_ID,
p_info.getAD_Table_ID(), p_info.getColumn(i).AD_Column_ID,
get_ID(), getAD_Client_ID(), getAD_Org_ID(), null, value, MChangeLog.EVENTCHANGELOG_Insert);
(m_IDs.length == 1 ? get_ID() : 0), get_UUID(), getAD_Client_ID(), getAD_Org_ID(), null, value, MChangeLog.EVENTCHANGELOG_Insert);
if (cLog != null)
AD_ChangeLog_ID = cLog.getAD_ChangeLog_ID();
}
@ -3843,16 +3858,17 @@ public abstract class PO
*/
public boolean delete (boolean force)
{
checkImmutable();
checkValidContext();
checkCrossTenant(true);
CLogger.resetLast();
if (is_new())
return true;
checkImmutable();
checkValidContext();
checkCrossTenant(true);
int AD_Table_ID = p_info.getAD_Table_ID();
int Record_ID = get_ID();
String Record_UU = get_UUID();
if (!force)
{
@ -3951,6 +3967,8 @@ public abstract class PO
}
// Delete Restrict AD_Table_ID/Record_ID (Requests, ..)
String errorMsg = PO_Record.exists(AD_Table_ID, Record_ID, m_trxName);
if (errorMsg == null && Record_UU != null)
errorMsg = PO_Record.exists(AD_Table_ID, Record_UU, m_trxName);
if (errorMsg != null)
{
log.saveError("CannotDelete", errorMsg);
@ -4000,9 +4018,14 @@ public abstract class PO
//delete cascade only for single key column record
PO_Record.deleteModelCascade(p_info.getTableName(), Record_ID, localTrxName);
// Delete Cascade AD_Table_ID/Record_ID (Attachments, ..)
PO_Record.deleteRecordIdCascade(AD_Table_ID, Record_ID, localTrxName);
PO_Record.deleteRecordCascade(AD_Table_ID, Record_ID, localTrxName);
// Set referencing Record_ID Null AD_Table_ID/Record_ID
PO_Record.setRecordIdNull(AD_Table_ID, Record_ID, localTrxName);
PO_Record.setRecordNull(AD_Table_ID, Record_ID, localTrxName);
}
if (Record_UU != null) {
PO_Record.deleteModelCascade(p_info.getTableName(), Record_UU, localTrxName);
PO_Record.deleteRecordCascade(AD_Table_ID, Record_UU, localTrxName);
PO_Record.setRecordNull(AD_Table_ID, Record_UU, localTrxName);
}
// The Delete Statement
@ -4082,7 +4105,7 @@ public abstract class PO
MChangeLog cLog = session.changeLog (
m_trxName != null ? m_trxName : localTrxName, AD_ChangeLog_ID,
AD_Table_ID, p_info.getColumn(i).AD_Column_ID,
Record_ID, getAD_Client_ID(), getAD_Org_ID(), value, null, MChangeLog.EVENTCHANGELOG_Delete);
(m_IDs.length == 1 ? Record_ID : 0), Record_UU, getAD_Client_ID(), getAD_Org_ID(), value, null, MChangeLog.EVENTCHANGELOG_Delete);
if (cLog != null)
AD_ChangeLog_ID = cLog.getAD_ChangeLog_ID();
}
@ -5765,6 +5788,52 @@ public abstract class PO
throw new AdempiereException("Cross tenant ID " + recordId + " not allowed in " + ft.getTableName());
}
/**
* Verify Foreign key based on AD_Table_ID+Record_UU for cross tenant
* @return true if all the foreign keys are valid
*/
private void checkRecordUUCrossTenant() {
if (isSafeCrossTenant.get())
return;
int idxRecordUU = p_info.getColumnIndex("Record_UU");
if (idxRecordUU < 0)
return;
int idxTableId = p_info.getColumnIndex("AD_Table_ID");
if (idxTableId < 0)
return;
if ( ! (is_new() || is_ValueChanged(idxTableId) || is_ValueChanged(idxRecordUU)))
return;
int tableId = get_ValueAsInt(idxTableId);
if (tableId <= 0)
return;
String recordUU = get_ValueAsString(idxRecordUU);
if (Util.isEmpty(recordUU))
return;
MTable ft = MTable.get(getCtx(), tableId);
if (!ft.hasUUIDKey())
return; // no UUID key in table
boolean systemAccess = false;
String accessLevel = ft.getAccessLevel();
if ( MTable.ACCESSLEVEL_All.equals(accessLevel)
|| MTable.ACCESSLEVEL_SystemOnly.equals(accessLevel)
|| MTable.ACCESSLEVEL_SystemPlusClient.equals(accessLevel)) {
systemAccess = true;
}
StringBuilder sql = new StringBuilder("SELECT AD_Client_ID FROM ")
.append(ft.getTableName())
.append(" WHERE ")
.append(PO.getUUIDColumnName(ft.getTableName()))
.append("=?");
int pocid = DB.getSQLValue(get_TrxName(), sql.toString(), recordUU);
if (pocid < 0)
throw new AdempiereException("Foreign UUID " + recordUU + " not found in " + ft.getTableName());
if (pocid == 0 && !systemAccess)
throw new AdempiereException("System UUID " + recordUU + " cannot be used in " + ft.getTableName());
int curcid = getAD_Client_ID();
if (pocid > 0 && pocid != curcid)
throw new AdempiereException("Cross tenant UUID " + recordUU + " not allowed in " + ft.getTableName());
}
/**
* Returns a list of indexes for the foreign columns, null if none
* @return array of int indexes

View File

@ -16,6 +16,7 @@
*****************************************************************************/
package org.compiere.model;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import java.util.logging.Level;
@ -39,92 +40,73 @@ public class PO_Record
/* Cache for arrays of KeyNamePair<AD_Table_ID, TableName> for types of deletion: Cascade, Set Null, No Action */
private static final CCache<String, KeyNamePair[]> s_po_record_tables_cache = new CCache<>(null, "PORecordTables", 100, 120, false);
/** Parent Tables */
private static int[] s_parents = new int[]{
X_C_Order.Table_ID
};
private static String[] s_parentNames = new String[]{
X_C_Order.Table_Name
};
private static int[] s_parentChilds = new int[]{
X_C_OrderLine.Table_ID
};
private static String[] s_parentChildNames = new String[]{
X_C_OrderLine.Table_Name
};
/** Logger */
private static CLogger log = CLogger.getCLogger (PO_Record.class);
/**
* Delete Cascade including (selected)parent relationships
* @param AD_Table_ID table
* @param Record_ID record
* @param Record_IDorUU record ID (int) or UUID (String)
* @param trxName transaction
* @return false if could not be deleted
*/
static boolean deleteRecordIdCascade (int AD_Table_ID, int Record_ID, String trxName)
protected static boolean deleteRecordCascade (int AD_Table_ID, Serializable Record_IDorUU, String trxName)
{
KeyNamePair[] cascades = getTablesWithRecordIDColumn(MColumn.FKCONSTRAINTTYPE_ModelCascade, trxName);
int refId;
String columnName;
if (Record_IDorUU instanceof Integer) {
refId = DisplayType.RecordID;
columnName = "Record_ID";
} else if (Record_IDorUU instanceof String) {
refId = DisplayType.RecordUU;
columnName = "Record_UU";
} else {
throw new IllegalArgumentException(Record_IDorUU.getClass().getName() + " not supported for ID/UUID");
}
KeyNamePair[] cascades = getTablesWithConstraintType(refId, MColumn.FKCONSTRAINTTYPE_ModelCascade, trxName);
// Table Loop
StringBuilder whereClause = new StringBuilder("AD_Table_ID=? AND ").append(columnName).append("=?");
for (KeyNamePair table : cascades)
{
// DELETE FROM table WHERE AD_Table_ID=#1 AND Record_ID=#2
List<PO> poList = new Query(Env.getCtx(), table.getName(), "AD_Table_ID=? AND Record_ID=?", trxName)
.setParameters(AD_Table_ID, Record_ID)
List<PO> poList = new Query(Env.getCtx(), table.getName(), whereClause.toString(), trxName)
.setParameters(AD_Table_ID, Record_IDorUU)
.list();
int count = 0;
for(PO po : poList)
{
if (po.get_Table_ID() == AD_Table_ID && po.get_ID() == Record_ID)
if ( po.get_Table_ID() == AD_Table_ID
&& ( (Record_IDorUU instanceof Integer && po.get_ID() == (Integer)Record_IDorUU)
|| (Record_IDorUU instanceof String && Record_IDorUU.equals(po.get_UUID()))
)
)
continue;
po.deleteEx(true);
count++;
}
if (count > 0)
if (log.isLoggable(Level.CONFIG)) log.config(table.getName() + " (" + AD_Table_ID + "/" + Record_ID + ") #" + count);
}
// Parent Loop
for (int i = 0; i < s_parents.length; i++)
{
if (s_parents[i] == AD_Table_ID)
{
int AD_Table_IDchild = s_parentChilds[i];
for (KeyNamePair table : cascades)
{
String whereClause = " AD_Table_ID=? AND Record_ID IN (SELECT "
+ s_parentChildNames[i] + "_ID FROM "
+ s_parentChildNames[i] + " WHERE "
+ s_parentNames[i] + "_ID=?) ";
List<PO> poList = new Query(Env.getCtx(), table.getName(), whereClause, trxName)
.setParameters(AD_Table_IDchild, Record_ID)
.list();
int count = 0;
for(PO po : poList)
{
po.deleteEx(true);
count++;
}
if(count > 0) {
if (log.isLoggable(Level.CONFIG)) log.config(table.getName() + " " + s_parentNames[i]
+ " (" + AD_Table_ID + "/" + Record_ID + ") #" + count);
}
}
}
if (log.isLoggable(Level.CONFIG)) log.config(table.getName() + " (" + AD_Table_ID + "/" + Record_IDorUU + ") #" + count);
}
return true;
} // deleteCascade
} // deleteRecordIdCascade
//IDEMPIERE-2060
/**
* @param tableName
* @param Record_ID
* @param Record_IDorUU record ID (int) or UUID (String)
* @param trxName
*/
public static void deleteModelCascade(String tableName, int Record_ID, String trxName) {
KeyNamePair[] tables = getTablesWithModelCascade(tableName, trxName);
public static void deleteModelCascade(String tableName, Serializable Record_IDorUU, String trxName) {
int refId;
if (Record_IDorUU instanceof Integer) {
refId = DisplayType.RecordID;
} else if (Record_IDorUU instanceof String) {
refId = DisplayType.RecordUU;
} else {
throw new IllegalArgumentException(Record_IDorUU.getClass().getName() + " not supported for ID/UUID");
}
KeyNamePair[] tables = getTablesWithModelCascade(refId, tableName, trxName);
for (KeyNamePair table : tables) {
int dependentTableId = table.getKey();
String dependentColumnName = table.getName();
@ -132,7 +114,7 @@ public class PO_Record
List<PO> poList = new Query(Env.getCtx(),
MTable.get(dependentTableId).getTableName(),
dependentWhere,
trxName).setParameters(Record_ID).list();
trxName).setParameters(Record_IDorUU).list();
for (PO po : poList) {
po.deleteEx(true, trxName);
}
@ -140,12 +122,27 @@ public class PO_Record
}
/**
* @param refId AD_Reference_ID - Record_ID or Record_UU
* @param tableName
* @param trxName
* @return
*/
private static KeyNamePair[] getTablesWithModelCascade(String tableName, String trxName) {
StringBuilder key = new StringBuilder(MColumn.FKCONSTRAINTTYPE_ModelCascade).append("|").append(tableName);
private static KeyNamePair[] getTablesWithModelCascade(int refId, String tableName, String trxName) {
int refTableDirId;
int refTableId;
int refTableSearchId;
if (refId == DisplayType.RecordID) {
refTableDirId = DisplayType.TableDir;
refTableId = DisplayType.Table;
refTableSearchId = DisplayType.Search;
} else if (refId == DisplayType.RecordUU) {
refTableDirId = DisplayType.TableDirUU;
refTableId = DisplayType.TableUU;
refTableSearchId = DisplayType.SearchUU;
} else {
throw new IllegalArgumentException(refId + " not supported for ID/UUID");
}
StringBuilder key = new StringBuilder(MColumn.FKCONSTRAINTTYPE_ModelCascade).append("|").append(refId).append("|").append(tableName);
KeyNamePair[] tables = s_po_record_tables_cache.get(key.toString());
if (tables != null)
return tables;
@ -159,12 +156,13 @@ public class PO_Record
+ "WHERE t.IsView = 'N' "
+ " AND t.IsActive = 'Y' "
+ " AND c.IsActive = 'Y' "
+ " AND ( ( c.AD_Reference_ID = " + DisplayType.TableDir
+ " AND ( ( c.AD_Reference_ID = ? "
+ " AND c.ColumnName = ? || '_ID' ) "
+ " OR ( c.AD_Reference_ID IN ( " + DisplayType.Table + ", " + DisplayType.Search + " ) "
+ " OR ( c.AD_Reference_ID IN (? , ?) "
+ " AND ( tr.TableName = ? OR ( tr.TableName IS NULL AND c.ColumnName = ? || '_ID' ) ) ) ) "
+ " AND c.FKConstraintType = '" + MColumn.FKCONSTRAINTTYPE_ModelCascade + "' ";
List<List<Object>> dependents = DB.getSQLArrayObjectsEx(trxName, sql, tableName, tableName, tableName);
+ " AND c.FKConstraintType = ?";
List<List<Object>> dependents = DB.getSQLArrayObjectsEx(trxName, sql,
refTableDirId, tableName, refTableId, refTableSearchId, tableName, tableName, MColumn.FKCONSTRAINTTYPE_ModelCascade);
if (dependents != null) {
tables = new KeyNamePair[dependents.size()];
for (int i=0; i<dependents.size(); i++) {
@ -184,30 +182,50 @@ public class PO_Record
/**
* If a referencing Record ID or Record UU exists to the deleted record, set it to NULL
* @param AD_Table_ID
* @param Record_ID
* @param Record_IDorUU record ID (int) or UUID (String)
* @param trxName
*/
public static void setRecordIdNull(int AD_Table_ID, int Record_ID, String trxName){
KeyNamePair[] tables = getTablesWithRecordIDColumn(MColumn.FKCONSTRAINTTYPE_ModelSetNull, trxName);
public static void setRecordNull(int AD_Table_ID, Serializable Record_IDorUU, String trxName){
int refId;
String columnName;
if (Record_IDorUU instanceof Integer) {
refId = DisplayType.RecordID;
columnName = "Record_ID";
} else if (Record_IDorUU instanceof String) {
refId = DisplayType.RecordUU;
columnName = "Record_UU";
} else {
throw new IllegalArgumentException(Record_IDorUU.getClass().getName() + " not supported for ID/UUID");
}
KeyNamePair[] tables = getTablesWithConstraintType(refId, MColumn.FKCONSTRAINTTYPE_ModelSetNull, trxName);
// Table loop
StringBuilder whereClause = new StringBuilder("AD_Table_ID=? AND ").append(columnName).append("=?");
for (KeyNamePair table : tables) {
List<PO> poList = new Query(Env.getCtx(), table.getName(), " AD_Table_ID = ? AND Record_ID = ? ", trxName)
.setParameters(AD_Table_ID, Record_ID)
List<PO> poList = new Query(Env.getCtx(), table.getName(), whereClause.toString(), trxName)
.setParameters(AD_Table_ID, Record_IDorUU)
.list();
int count = 0;
for(PO po : poList) {
if (po.get_Table_ID() == AD_Table_ID && po.get_ID() == Record_ID)
if ( po.get_Table_ID() == AD_Table_ID
&& ( (Record_IDorUU instanceof Integer && po.get_ID() == (Integer) Record_IDorUU)
|| (Record_IDorUU instanceof String && Record_IDorUU.equals(po.get_UUID()))
)
)
continue;
if (po.isColumnMandatory(po.get_ColumnIndex("Record_ID")))
po.set_Value("Record_ID", 0);
else
po.set_Value("Record_ID", null);
if (po.isColumnMandatory(po.get_ColumnIndex(columnName))) {
if (Record_IDorUU instanceof Integer)
po.set_Value(columnName, 0);
else
po.set_Value(columnName, "");
} else {
po.set_Value(columnName, null);
}
po.saveEx(trxName);
count++;
}
if (count > 0) {
if (log.isLoggable(Level.CONFIG)) log.config(table.getName() + " (" + AD_Table_ID + "/" + Record_ID + ") #" + count);
if (log.isLoggable(Level.CONFIG)) log.config(table.getName() + " (" + AD_Table_ID + "/" + Record_IDorUU + ") #" + count);
}
}
}
@ -215,22 +233,34 @@ public class PO_Record
/**
* An entry Exists for restrict table/record combination
* @param AD_Table_ID table
* @param Record_ID record
* @param Record_IDorUU record ID (int) or UUID (String)
* @param trxName transaction
* @return error message (Table Name) or null
*/
static String exists (int AD_Table_ID, int Record_ID, String trxName)
protected static String exists (int AD_Table_ID, Serializable Record_IDorUU, String trxName)
{
KeyNamePair[] restricts = getTablesWithRecordIDColumn(MColumn.FKCONSTRAINTTYPE_ModelNoAction_ForbidDeletion, trxName);
int refId;
String columnName;
if (Record_IDorUU instanceof Integer) {
refId = DisplayType.RecordID;
columnName = "Record_ID";
} else if (Record_IDorUU instanceof String) {
refId = DisplayType.RecordUU;
columnName = "Record_UU";
} else {
log.warning(Record_IDorUU.getClass().getName() + " not supported for ID/UUID");
return null;
}
KeyNamePair[] restricts = getTablesWithConstraintType(refId, MColumn.FKCONSTRAINTTYPE_ModelNoAction_ForbidDeletion, trxName);
// Table Loop only
for (int i = 0; i < restricts.length; i++)
{
// SELECT 1 FROM table WHERE AD_Table_ID=#1 AND Record_ID=#2 FETCH FIRST 1 ROWS ONLY
StringBuilder sqlb = new StringBuilder ("SELECT 1 FROM ")
.append(restricts[i].getName())
.append(" WHERE AD_Table_ID=? AND Record_ID=?");
.append(" WHERE AD_Table_ID=? AND ").append(columnName).append("=?");
String sql = DB.getDatabase().addPagingSQL(sqlb.toString(), 1, 1);
int no = DB.getSQLValueEx(trxName, sql.toString(), AD_Table_ID, Record_ID);
int no = DB.getSQLValueEx(trxName, sql.toString(), AD_Table_ID, Record_IDorUU);
if (no == 1)
return Msg.getMsg(Env.getCtx(), "DeleteErrorDependent") + " -> " + restricts[i].getName();
}
@ -238,26 +268,37 @@ public class PO_Record
} // exists
/**
* Get array of tables which has a Record_ID column with the defined Constraint Type
* Get array of tables which has a refId column with the defined Constraint Type
* @param refId AD_Reference_ID - Record_ID or Record_UU
* @param constraintType - FKConstraintType of AD_Column
* @param trxName
* @return array of KeyNamePair<AD_Table_ID, TableName>
*/
private static KeyNamePair[] getTablesWithRecordIDColumn(String constraintType, String trxName) {
KeyNamePair[] tables = s_po_record_tables_cache.get(constraintType);
private static KeyNamePair[] getTablesWithConstraintType(int refId, String constraintType, String trxName) {
String columnName;
if (refId == DisplayType.RecordID) {
columnName = "Record_ID";
} else if (refId == DisplayType.RecordUU) {
columnName = "Record_UU";
} else {
log.warning(refId + " not supported for ID/UUID");
return null;
}
StringBuilder key = new StringBuilder(constraintType).append("|").append(refId);
KeyNamePair[] tables = s_po_record_tables_cache.get(key.toString());
if (tables != null)
return tables;
List<MTable> listTables = new Query(Env.getCtx(), MTable.Table_Name, "c.AD_Reference_ID=? AND c.FKConstraintType=? AND AD_Table.IsView='N'", trxName)
List<MTable> listTables = new Query(Env.getCtx(), MTable.Table_Name, "c.AD_Reference_ID=? AND c.FKConstraintType=? AND AD_Table.IsView='N' AND c.ColumnName=?", trxName)
.addJoinClause("JOIN AD_Column c ON (c.AD_Table_ID=AD_Table.AD_Table_ID)")
.setOnlyActiveRecords(true)
.setParameters(DisplayType.RecordID, constraintType)
.setParameters(refId, constraintType, columnName)
.list();
tables = new KeyNamePair[listTables.size()];
for (int i=0; i<listTables.size(); i++) {
MTable table = listTables.get(i);
tables[i] = new KeyNamePair(table.getAD_Table_ID(), table.getTableName());
}
s_po_record_tables_cache.put(constraintType, tables);
s_po_record_tables_cache.put(key.toString(), tables);
return tables;
}

View File

@ -31,7 +31,7 @@ public class X_AD_ChangeLog extends PO implements I_AD_ChangeLog, I_Persistent
/**
*
*/
private static final long serialVersionUID = 20230409L;
private static final long serialVersionUID = 20230415L;
/** Standard Constructor */
public X_AD_ChangeLog (Properties ctx, int AD_ChangeLog_ID, String trxName)
@ -44,7 +44,6 @@ public class X_AD_ChangeLog extends PO implements I_AD_ChangeLog, I_Persistent
setAD_Session_ID (0);
setAD_Table_ID (0);
setIsCustomization (false);
setRecord_ID (0);
} */
}
@ -59,7 +58,6 @@ public class X_AD_ChangeLog extends PO implements I_AD_ChangeLog, I_Persistent
setAD_Session_ID (0);
setAD_Table_ID (0);
setIsCustomization (false);
setRecord_ID (0);
} */
}
@ -74,7 +72,6 @@ public class X_AD_ChangeLog extends PO implements I_AD_ChangeLog, I_Persistent
setAD_Session_ID (0);
setAD_Table_ID (0);
setIsCustomization (false);
setRecord_ID (0);
} */
}
@ -89,7 +86,6 @@ public class X_AD_ChangeLog extends PO implements I_AD_ChangeLog, I_Persistent
setAD_Session_ID (0);
setAD_Table_ID (0);
setIsCustomization (false);
setRecord_ID (0);
} */
}
@ -368,6 +364,21 @@ public class X_AD_ChangeLog extends PO implements I_AD_ChangeLog, I_Persistent
return ii.intValue();
}
/** Set Record UUID.
@param Record_UU Record UUID
*/
public void setRecord_UU (String Record_UU)
{
set_ValueNoCheck (COLUMNNAME_Record_UU, Record_UU);
}
/** Get Record UUID.
@return Record UUID */
public String getRecord_UU()
{
return (String)get_Value(COLUMNNAME_Record_UU);
}
/** Set Redo.
@param Redo Redo
*/

View File

@ -46,6 +46,7 @@ import org.compiere.util.DisplayType;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.compiere.util.NamePair;
import org.compiere.util.Util;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
@ -62,10 +63,15 @@ import org.zkoss.zul.South;
*/
public class WFieldRecordInfo extends Window implements EventListener<Event>
{
private static final long serialVersionUID = 3859352394520596098L;
/**
*
*/
private static final long serialVersionUID = 439310027130417727L;
private int AD_Table_ID;
private int AD_Column_ID;
private int Record_ID;
private String Record_UU;
/**
* Record Info
@ -73,8 +79,9 @@ public class WFieldRecordInfo extends Window implements EventListener<Event>
* @param AD_Table_ID
* @param AD_Column_ID
* @param Record_ID
* @param Record_UU
*/
public WFieldRecordInfo (String title, int AD_Table_ID, int AD_Column_ID, int Record_ID)
public WFieldRecordInfo (String title, int AD_Table_ID, int AD_Column_ID, int Record_ID, String Record_UU)
{
super ();
this.setTitle(title);
@ -99,7 +106,8 @@ public class WFieldRecordInfo extends Window implements EventListener<Event>
this.AD_Table_ID = AD_Table_ID;
this.AD_Column_ID = AD_Column_ID;
this.Record_ID = Record_ID;
this.Record_UU = Record_UU;
try
{
init ( dynInit(title) );
@ -186,13 +194,13 @@ public class WFieldRecordInfo extends Window implements EventListener<Event>
if (!MRole.PREFERENCETYPE_Client.equals(MRole.getDefault().getPreferenceType()))
return false;
if (Record_ID == 0)
if (Record_ID == 0 && Util.isEmpty(Record_UU))
return false;
// Data
String sql = "SELECT AD_Column_ID, Updated, UpdatedBy, OldValue, NewValue "
+ "FROM AD_ChangeLog "
+ "WHERE AD_Table_ID=? AND Record_ID=? AND AD_Column_ID=? "
+ "WHERE AD_Table_ID=? AND (Record_ID=? OR Record_UU=?) AND AD_Column_ID=? "
+ "ORDER BY Updated DESC";
PreparedStatement pstmt = null;
ResultSet rs = null;
@ -201,7 +209,8 @@ public class WFieldRecordInfo extends Window implements EventListener<Event>
pstmt = DB.prepareStatement (sql, null);
pstmt.setInt (1, AD_Table_ID);
pstmt.setInt (2, Record_ID);
pstmt.setInt (3, AD_Column_ID);
pstmt.setString (3, Record_UU);
pstmt.setInt (4, AD_Column_ID);
rs = pstmt.executeQuery ();
while (rs.next ())
{
@ -379,7 +388,8 @@ public class WFieldRecordInfo extends Window implements EventListener<Event>
public static void start(GridField gridField) {
new WFieldRecordInfo(gridField.getColumnName(),
gridField.getGridTab().getAD_Table_ID(), gridField.getAD_Column_ID(),
gridField.getGridTab().getRecord_ID());
gridField.getGridTab().getRecord_ID(),
gridField.getGridTab().getRecord_UU());
}
/**

View File

@ -317,6 +317,7 @@ public class WRecordInfo extends Window implements EventListener<Event>
int Record_ID = -1;
if (dse.Record_ID instanceof Integer)
Record_ID = ((Integer)dse.Record_ID).intValue();
String Record_UU = null;
MTable dbtable = null;
if (dse.AD_Table_ID != 0)
@ -327,7 +328,6 @@ public class WRecordInfo extends Window implements EventListener<Event>
PO po = gridTable.getPO(dse.getCurrentRow());
if (po != null) {
String uuidcol = po.getUUIDColumnName();
String uuid = null;
if (po.is_new()) {
if (Record_ID == 0 && MTable.isZeroIDTable(dbtable.getTableName())) {
// Need to read the UUID directly from database because the PO cannot be used with zero ID records
@ -338,13 +338,13 @@ public class WRecordInfo extends Window implements EventListener<Event>
.append(" WHERE ")
.append(dbtable.getTableName())
.append("_ID=0");
uuid = DB.getSQLValueString(null, sql.toString());
Record_UU = DB.getSQLValueString(null, sql.toString());
}
} else {
uuid = po.get_UUID();
Record_UU = po.get_UUID();
}
if (!Util.isEmpty(uuid)) {
StringBuilder uuinfo = new StringBuilder(uuidcol).append("=").append(uuid);
if (!Util.isEmpty(Record_UU)) {
StringBuilder uuinfo = new StringBuilder(uuidcol).append("=").append(Record_UU);
if (! m_info.toString().contains(uuinfo))
m_info.append("\n ").append(uuinfo);
}
@ -365,7 +365,7 @@ public class WRecordInfo extends Window implements EventListener<Event>
});
}
m_permalink.setVisible(po.get_KeyColumns().length == 1);
final String whereClause = po.get_WhereClause(true, uuid);
final String whereClause = po.get_WhereClause(true, Record_UU);
m_copySelect.addEventListener(Events.ON_CLICK, new EventListener<Event>() {
public void onEvent(Event event) throws Exception {
StringBuffer query = new StringBuffer("navigator.clipboard.writeText(\"SELECT * FROM ")
@ -396,13 +396,13 @@ public class WRecordInfo extends Window implements EventListener<Event>
if (!MRole.PREFERENCETYPE_Client.equals(MRole.getDefault().getPreferenceType()))
return false;
if (Record_ID <= 0)
if (Record_ID <= 0 && Util.isEmpty(Record_UU))
return false;
// Data
String sql = "SELECT AD_Column_ID, Updated, UpdatedBy, OldValue, NewValue "
+ "FROM AD_ChangeLog "
+ "WHERE AD_Table_ID=? AND Record_ID=? "
+ "WHERE AD_Table_ID=? AND (Record_ID=? OR Record_UU=?) "
+ "ORDER BY Updated DESC";
PreparedStatement pstmt = null;
ResultSet rs = null;
@ -411,6 +411,7 @@ public class WRecordInfo extends Window implements EventListener<Event>
pstmt = DB.prepareStatement (sql, null);
pstmt.setInt (1, dse.AD_Table_ID);
pstmt.setInt (2, Record_ID);
pstmt.setString (3, Record_UU);
rs = pstmt.executeQuery ();
while (rs.next ())
{