diff --git a/migration/iD11/oracle/202304151832_IDEMPIERE-5567.sql b/migration/iD11/oracle/202304151832_IDEMPIERE-5567.sql new file mode 100644 index 0000000000..b75108dee7 --- /dev/null +++ b/migration/iD11/oracle/202304151832_IDEMPIERE-5567.sql @@ -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; +/ +*/ + diff --git a/migration/iD11/postgresql/202304151832_IDEMPIERE-5567.sql b/migration/iD11/postgresql/202304151832_IDEMPIERE-5567.sql new file mode 100644 index 0000000000..d57d7f7558 --- /dev/null +++ b/migration/iD11/postgresql/202304151832_IDEMPIERE-5567.sql @@ -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; +$$ +; +*/ + diff --git a/org.adempiere.base/src/org/compiere/model/GridTab.java b/org.adempiere.base/src/org/compiere/model/GridTab.java index 9cb0ef6f4b..ea812cc1b2 100644 --- a/org.adempiere.base/src/org/compiere/model/GridTab.java +++ b/org.adempiere.base/src/org/compiere/model/GridTab.java @@ -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 diff --git a/org.adempiere.base/src/org/compiere/model/I_AD_ChangeLog.java b/org.adempiere.base/src/org/compiere/model/I_AD_ChangeLog.java index 4f13a6da3d..95a7b600ef 100644 --- a/org.adempiere.base/src/org/compiere/model/I_AD_ChangeLog.java +++ b/org.adempiere.base/src/org/compiere/model/I_AD_ChangeLog.java @@ -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"; diff --git a/org.adempiere.base/src/org/compiere/model/MChangeLog.java b/org.adempiere.base/src/org/compiere/model/MChangeLog.java index 36cde1bffc..dff8d3d0f1 100644 --- a/org.adempiere.base/src/org/compiere/model/MChangeLog.java +++ b/org.adempiere.base/src/org/compiere/model/MChangeLog.java @@ -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); // diff --git a/org.adempiere.base/src/org/compiere/model/MLookup.java b/org.adempiere.base/src/org/compiere/model/MLookup.java index 617275826d..8a9d464bc3 100644 --- a/org.adempiere.base/src/org/compiere/model/MLookup.java +++ b/org.adempiere.base/src/org/compiere/model/MLookup.java @@ -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 diff --git a/org.adempiere.base/src/org/compiere/model/MSession.java b/org.adempiere.base/src/org/compiere/model/MSession.java index 975c4f3883..92a8bd36f1 100644 --- a/org.adempiere.base/src/org/compiere/model/MSession.java +++ b/org.adempiere.base/src/org/compiere/model/MSession.java @@ -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; diff --git a/org.adempiere.base/src/org/compiere/model/MSysConfig.java b/org.adempiere.base/src/org/compiere/model/MSysConfig.java index 945733dfd7..99ed8e1a87 100644 --- a/org.adempiere.base/src/org/compiere/model/MSysConfig.java +++ b/org.adempiere.base/src/org/compiere/model/MSysConfig.java @@ -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"; diff --git a/org.adempiere.base/src/org/compiere/model/MTable.java b/org.adempiere.base/src/org/compiere/model/MTable.java index ca9039b67e..bc127b896a 100644 --- a/org.adempiere.base/src/org/compiere/model/MTable.java +++ b/org.adempiere.base/src/org/compiere/model/MTable.java @@ -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") || diff --git a/org.adempiere.base/src/org/compiere/model/PO.java b/org.adempiere.base/src/org/compiere/model/PO.java index 5f7c569e93..d88a963dda 100644 --- a/org.adempiere.base/src/org/compiere/model/PO.java +++ b/org.adempiere.base/src/org/compiere/model/PO.java @@ -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 diff --git a/org.adempiere.base/src/org/compiere/model/PO_Record.java b/org.adempiere.base/src/org/compiere/model/PO_Record.java index 038cd0b69c..d26daaa888 100644 --- a/org.adempiere.base/src/org/compiere/model/PO_Record.java +++ b/org.adempiere.base/src/org/compiere/model/PO_Record.java @@ -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 for types of deletion: Cascade, Set Null, No Action */ private static final CCache 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 poList = new Query(Env.getCtx(), table.getName(), "AD_Table_ID=? AND Record_ID=?", trxName) - .setParameters(AD_Table_ID, Record_ID) + List 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 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 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> dependents = DB.getSQLArrayObjectsEx(trxName, sql, tableName, tableName, tableName); + + " AND c.FKConstraintType = ?"; + List> 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 poList = new Query(Env.getCtx(), table.getName(), " AD_Table_ID = ? AND Record_ID = ? ", trxName) - .setParameters(AD_Table_ID, Record_ID) + List 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 */ - 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 listTables = new Query(Env.getCtx(), MTable.Table_Name, "c.AD_Reference_ID=? AND c.FKConstraintType=? AND AD_Table.IsView='N'", trxName) + List 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 { - 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 * @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 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 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 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 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()); } /** diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/WRecordInfo.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/WRecordInfo.java index f80be8ff0f..dc33ea856d 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/WRecordInfo.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/WRecordInfo.java @@ -317,6 +317,7 @@ public class WRecordInfo extends Window implements EventListener 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 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 .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 }); } 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() { 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 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 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 ()) {