IDEMPIERE-5586 Implement ID independent migration script (#1685)

* IDEMPIERE-5586 Implement ID independent migration script

* IDEMPIERE-5586 Implement ID independent migration script

- add Oracle script (99% converted by ChatGPT from PostgreSQL :)).

* IDEMPIERE-5586 Implement ID independent migration script

- handle official id value for foreign key reference .
- add back centralized id support.

* IDEMPIERE-5586 Implement ID independent migration script

- minor refactoring
- add support for AD_Table_ID+Record_ID usage

* IDEMPIERE-5586 Implement ID independent migration script

- add support for Delete
- add unit test

* IDEMPIERE-5586 Implement ID independent migration script

- add insert_accounting and insert_tree support.

* IDEMPIERE-5586 Implement ID independent migration script

- add ADSortTab support.

* IDEMPIERE-5586 Implement ID independent migration script

- move migration script from iD11 to iD10.
This commit is contained in:
hengsin 2023-03-03 01:24:41 +08:00 committed by GitHub
parent a69162fff8
commit 6a66903ec6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 700 additions and 136 deletions

View File

@ -0,0 +1,41 @@
CREATE OR REPLACE FUNCTION torecordid (
p_tablename IN VARCHAR2,
p_uu_value IN VARCHAR2
)
RETURN NUMBER AS
id_column VARCHAR2(200);
uu_column VARCHAR2(200);
o_id NUMBER;
BEGIN
SELECT a.ColumnName
INTO id_column
FROM AD_Column a
JOIN AD_Table b ON (a.AD_Table_ID=b.AD_Table_ID)
WHERE a.IsActive='Y' AND a.IsKey='Y' AND lower(b.TableName) = lower(p_tablename);
IF (id_column IS NULL) THEN
raise_application_error(-20001, 'ID column not found for table ' || p_tablename);
END IF;
IF (length(p_tablename) <= 27) THEN
uu_column := p_tablename || '_UU';
ELSE
SELECT a.ColumnName
INTO uu_column
FROM AD_Column a
JOIN AD_Table b ON (a.AD_Table_ID=b.AD_Table_ID)
WHERE a.IsActive='Y' AND a.FieldLength=36 AND lower(a.ColumnName) LIKE (lower(SUBSTR(p_tablename, 1, 27)) || '%UU')
AND lower(b.TableName) = lower(p_tablename);
END IF;
IF (uu_column IS NULL) THEN
raise_application_error(-20002, 'UUID column not found for table ' || p_tablename);
END IF;
EXECUTE IMMEDIATE 'SELECT ' || id_column || ' FROM ' || p_tablename || ' WHERE ' || uu_column || '=:1'
INTO o_id
USING p_uu_value;
RETURN o_id;
END;
/

View File

@ -0,0 +1,42 @@
CREATE OR REPLACE FUNCTION torecordid(
p_tablename IN VARCHAR,
p_uu_value IN VARCHAR
)
RETURNS INTEGER AS $body$
DECLARE
id_column VARCHAR;
uu_column VARCHAR;
o_id INTEGER;
BEGIN
SELECT a.ColumnName
INTO id_column
FROM AD_Column a
JOIN AD_Table b ON (a.AD_Table_ID=b.AD_Table_ID)
WHERE a.IsActive='Y' AND a.IsKey='Y' AND lower(b.TableName) = lower(p_tablename);
IF (id_column IS NULL) THEN
RAISE EXCEPTION 'ID column not found for table %', p_tablename;
END IF;
IF (length(p_tablename) <= 27) THEN
uu_column = p_tablename || '_UU';
ELSE
SELECT a.ColumnName
INTO uu_column
FROM AD_Column a
JOIN AD_Table b ON (a.AD_Table_ID=b.AD_Table_ID)
WHERE a.IsActive='Y' AND a.FieldLength=36 AND lower(ColumnName) like (lower(substring(p_tablename from 0 for 27)) || '%UU')
AND lower(b.TableName) = lower(p_tablename);
END IF;
IF (uu_column IS NULL) THEN
RAISE EXCEPTION 'UUID column not found for table %', p_tablename;
END IF;
EXECUTE 'SELECT ' || quote_ident(lower(id_column)) || ' FROM ' || quote_ident(lower(p_tablename)) || ' WHERE ' || uu_column || '=$1'
INTO STRICT o_id
USING p_uu_value;
RETURN o_id;
END;
$body$ LANGUAGE plpgsql;

View File

@ -0,0 +1,47 @@
-- IDEMPIERE-5586
SELECT register_migration_script('202302220654_IDEMPIERE-5586.sql') FROM dual;
SET SQLBLANKLINES ON
SET DEFINE OFF
CREATE OR REPLACE FUNCTION torecordid (
p_tablename IN VARCHAR2,
p_uu_value IN VARCHAR2
)
RETURN NUMBER AS
id_column VARCHAR2(200);
uu_column VARCHAR2(200);
o_id NUMBER;
BEGIN
SELECT a.ColumnName
INTO id_column
FROM AD_Column a
JOIN AD_Table b ON (a.AD_Table_ID=b.AD_Table_ID)
WHERE a.IsActive='Y' AND a.IsKey='Y' AND lower(b.TableName) = lower(p_tablename);
IF (id_column IS NULL) THEN
raise_application_error(-20001, 'ID column not found for table ' || p_tablename);
END IF;
IF (length(p_tablename) <= 27) THEN
uu_column := p_tablename || '_UU';
ELSE
SELECT a.ColumnName
INTO uu_column
FROM AD_Column a
JOIN AD_Table b ON (a.AD_Table_ID=b.AD_Table_ID)
WHERE a.IsActive='Y' AND a.FieldLength=36 AND lower(a.ColumnName) LIKE (lower(SUBSTR(p_tablename, 1, 27)) || '%UU')
AND lower(b.TableName) = lower(p_tablename);
END IF;
IF (uu_column IS NULL) THEN
raise_application_error(-20002, 'UUID column not found for table ' || p_tablename);
END IF;
EXECUTE IMMEDIATE 'SELECT ' || id_column || ' FROM ' || p_tablename || ' WHERE ' || uu_column || '=:1'
INTO o_id
USING p_uu_value;
RETURN o_id;
END;
/

View File

@ -0,0 +1,48 @@
-- IDEMPIERE-5586
SELECT register_migration_script('202302220654_IDEMPIERE-5586.sql') FROM dual;
CREATE OR REPLACE FUNCTION torecordid(
p_tablename IN VARCHAR,
p_uu_value IN VARCHAR
)
RETURNS INTEGER AS $body$
DECLARE
id_column VARCHAR;
uu_column VARCHAR;
o_id INTEGER;
BEGIN
SELECT a.ColumnName
INTO id_column
FROM AD_Column a
JOIN AD_Table b ON (a.AD_Table_ID=b.AD_Table_ID)
WHERE a.IsActive='Y' AND a.IsKey='Y' AND lower(b.TableName) = lower(p_tablename);
IF (id_column IS NULL) THEN
RAISE EXCEPTION 'ID column not found for table %', p_tablename;
END IF;
IF (length(p_tablename) <= 27) THEN
uu_column = p_tablename || '_UU';
ELSE
SELECT a.ColumnName
INTO uu_column
FROM AD_Column a
JOIN AD_Table b ON (a.AD_Table_ID=b.AD_Table_ID)
WHERE a.IsActive='Y' AND a.FieldLength=36 AND lower(ColumnName) like (lower(substring(p_tablename from 0 for 27)) || '%UU')
AND lower(b.TableName) = lower(p_tablename);
END IF;
IF (uu_column IS NULL) THEN
RAISE EXCEPTION 'UUID column not found for table %', p_tablename;
END IF;
EXECUTE 'SELECT ' || quote_ident(lower(id_column)) || ' FROM ' || quote_ident(lower(p_tablename)) || ' WHERE ' || uu_column || '=$1'
INTO STRICT o_id
USING p_uu_value;
RETURN o_id;
END;
$body$ LANGUAGE plpgsql
;

View File

@ -42,10 +42,12 @@ import java.util.regex.Pattern;
import org.adempiere.exceptions.AdempiereException;
import org.compiere.Adempiere;
import org.compiere.db.Database;
import org.compiere.model.I_AD_UserPreference;
import org.compiere.util.CLogger;
import org.compiere.util.DisplayType;
import org.compiere.util.Env;
import org.compiere.util.Ini;
import org.compiere.util.Util;
/**
* Convert SQL to Target DB
@ -441,6 +443,11 @@ public abstract class Convert
*/
public abstract boolean isOracle();
/**
* Log oraStatement and pgStatement to SQL migration script file.
* @param oraStatement
* @param pgStatement
*/
public synchronized static void logMigrationScript(String oraStatement, String pgStatement) {
// Check AdempiereSys
// check property Log migration script
@ -456,26 +463,10 @@ public abstract class Convert
String prm_COMMENT = null;
try {
if (fosScriptOr == null || fosScriptPg == null) {
String now = new SimpleDateFormat("yyyyMMddHHmm").format(new Date());
prm_COMMENT = Env.getContext(Env.getCtx(), "MigrationScriptComment");
String pattern = "(IDEMPIERE-[0-9]*)";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(prm_COMMENT);
String ticket = null;
if (m.find())
ticket = m.group(1);
if (ticket == null)
ticket = "PlaceholderForTicket";
fileName = now + "_" + ticket + ".sql";
String version = Adempiere.MAIN_VERSION.substring(8);
boolean isIDE = Files.isDirectory(Paths.get(Adempiere.getAdempiereHome() + File.separator + "org.adempiere.base"));
String homeScript;
if (isIDE)
homeScript = Adempiere.getAdempiereHome() + File.separator;
else
homeScript = System.getProperty("java.io.tmpdir") + File.separator;
folderOr = homeScript + "migration" + File.separator + "iD" + version + File.separator + "oracle" + File.separator;
folderPg = homeScript + "migration" + File.separator + "iD" + version + File.separator + "postgresql" + File.separator;
prm_COMMENT = Env.getContext(Env.getCtx(), I_AD_UserPreference.COLUMNNAME_MigrationScriptComment);
fileName = getMigrationScriptFileName(prm_COMMENT);
folderOr = getMigrationScriptFolder("oracle");
folderPg = getMigrationScriptFolder("postgresql");
Files.createDirectories(Paths.get(folderOr));
Files.createDirectories(Paths.get(folderPg));
}
@ -511,6 +502,42 @@ public abstract class Convert
}
}
/**
* @param ticketComment
* @return migration script file name
*/
public static String getMigrationScriptFileName(String ticketComment) {
// [timestamp]_[ticket].sql
String fileName;
String now = new SimpleDateFormat("yyyyMMddHHmm").format(new Date());
String pattern = "(IDEMPIERE-[0-9]*)";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(ticketComment);
String ticket = null;
if (m.find())
ticket = m.group(1);
if (ticket == null)
ticket = "PlaceholderForTicket";
fileName = now + "_" + ticket + ".sql";
return fileName;
}
/**
* @param dbtype oracle or postgresql
* @return absolute migration script folder path for dbtype
*/
public static String getMigrationScriptFolder(String dbtype) {
// migration/iD[version]/[oracle|postgresql] directory
String version = Adempiere.MAIN_VERSION.substring(8);
boolean isIDE = Files.isDirectory(Paths.get(Adempiere.getAdempiereHome() + File.separator + "org.adempiere.base"));
String homeScript;
if (isIDE)
homeScript = Adempiere.getAdempiereHome() + File.separator;
else
homeScript = System.getProperty("java.io.tmpdir") + File.separator;
return homeScript + "migration" + File.separator + "iD" + version + File.separator + dbtype + File.separator;
}
/**
* @return true if it is in log migration script mode
*/
@ -519,13 +546,12 @@ public abstract class Convert
if (Ini.isClient()) {
logMigrationScript = Ini.isPropertyBool(Ini.P_LOGMIGRATIONSCRIPT);
} else {
String sysProperty = Env.getCtx().getProperty("LogMigrationScript", "N");
String sysProperty = Env.getCtx().getProperty(Ini.P_LOGMIGRATIONSCRIPT, "N");
logMigrationScript = "y".equalsIgnoreCase(sysProperty) || "true".equalsIgnoreCase(sysProperty);
}
return logMigrationScript;
}
private static String [] dontLogTables = new String[] {
"AD_ACCESSLOG",
"AD_ALERTPROCESSORLOG",
@ -573,6 +599,25 @@ public abstract class Convert
"T_TRIALBALANCE"
};
/**
* @param tableName
* @return true if log migration script should ignore tableName
*/
public static boolean isDontLogTable(String tableName) {
if (Util.isEmpty(tableName))
return false;
// Don't log trl - those will be created/maintained using synchronize terminology
if (tableName.endsWith("_TRL"))
return true;
for (String t : dontLogTables) {
if (t.equalsIgnoreCase(tableName))
return true;
}
return false;
}
private static boolean dontLog(String statement) {
// Do not log *Access records - teo_Sarca BF [ 2782095 ]
// IDEMPIERE-323 Migration script log AD_Document_Action_Access (nmicoud / CarlosRuiz_globalqss)
@ -599,6 +644,8 @@ public abstract class Convert
return true;
if (uppStmt.matches("INSERT INTO .*_TRL .*"))
return true;
if (uppStmt.matches("DELETE FROM .*_TRL .*"))
return true;
// Don't log tree custom table statements (not present in core)
if (uppStmt.startsWith("INSERT INTO AD_TREENODE ") && uppStmt.contains(" AND T.TREETYPE='TL' AND T.AD_TABLE_ID="))
return true;
@ -619,6 +666,12 @@ public abstract class Convert
return false;
}
/**
* Use writer to append SQL statement to an output media (usually file).
* @param w {@link Writer}
* @param statement SQL statement
* @throws IOException
*/
private static void writeLogMigrationScript(Writer w, String statement) throws IOException
{
// log time and date

View File

@ -989,7 +989,10 @@ public class MBPartner extends X_C_BPartner implements ImmutablePOSupport
// Trees
insert_Tree(MTree_Base.TREETYPE_BPartner);
// Accounting
StringBuilder msgacc = new StringBuilder("p.C_BP_Group_ID=").append(getC_BP_Group_ID());
StringBuilder msgacc = new StringBuilder("p.C_BP_Group_ID=")
.append(getC_BP_Group_ID() > MTable.MAX_OFFICIAL_ID && Env.isLogMigrationScript(get_TableName())
? "toRecordId('C_BP_Group',"+DB.TO_STRING(MBPGroup.get(getC_BP_Group_ID()).getC_BP_Group_UU())+")"
: getC_BP_Group_ID());
insert_Accounting("C_BP_Customer_Acct", "C_BP_Group_Acct", msgacc.toString());
insert_Accounting("C_BP_Vendor_Acct", "C_BP_Group_Acct",msgacc.toString());
}

View File

@ -854,7 +854,10 @@ public class MProduct extends X_M_Product implements ImmutablePOSupport
if (newRecord)
{
insert_Accounting("M_Product_Acct", "M_Product_Category_Acct",
"p.M_Product_Category_ID=" + getM_Product_Category_ID());
"p.M_Product_Category_ID=" +
(getM_Product_Category_ID() > MTable.MAX_OFFICIAL_ID && Env.isLogMigrationScript(get_TableName())
? "toRecordId('M_Product_Category',"+DB.TO_STRING(MProductCategory.get(getM_Product_Category_ID()).getM_Product_Category_UU())+")"
: getM_Product_Category_ID()));
insert_Tree(X_AD_Tree.TREETYPE_Product);
}
if (newRecord || is_ValueChanged(COLUMNNAME_Value))

View File

@ -86,7 +86,7 @@ public class MSequence extends X_AD_Sequence
}
else
{
String sysProperty = Env.getCtx().getProperty("AdempiereSys", "N");
String sysProperty = Env.getCtx().getProperty(Ini.P_ADEMPIERESYS, "N");
adempiereSys = "y".equalsIgnoreCase(sysProperty) || "true".equalsIgnoreCase(sysProperty);
}
if (adempiereSys && AD_Client_ID > 11)
@ -315,7 +315,7 @@ public class MSequence extends X_AD_Sequence
}
else
{
String sysProperty = Env.getCtx().getProperty("AdempiereSys", "N");
String sysProperty = Env.getCtx().getProperty(Ini.P_ADEMPIERESYS, "N");
adempiereSys = "y".equalsIgnoreCase(sysProperty) || "true".equalsIgnoreCase(sysProperty);
}
if (adempiereSys && Env.getAD_Client_ID(Env.getCtx()) > 11)
@ -1103,7 +1103,7 @@ public class MSequence extends X_AD_Sequence
String prm_PASSWORD = MSysConfig.getValue(MSysConfig.DICTIONARY_ID_PASSWORD); // "password_inseguro";
String prm_TABLE = TableName;
String prm_ALTKEY = ""; // TODO: generate alt-key based on key of table
String prm_COMMENT = Env.getContext(Env.getCtx(), "MigrationScriptComment");
String prm_COMMENT = Env.getContext(Env.getCtx(), I_AD_UserPreference.COLUMNNAME_MigrationScriptComment);
String prm_PROJECT = new String("Adempiere");
return getNextID_HTTP(TableName, website, prm_USER,
@ -1122,7 +1122,7 @@ public class MSequence extends X_AD_Sequence
String prm_PASSWORD = MSysConfig.getValue(MSysConfig.PROJECT_ID_PASSWORD); // "password_inseguro";
String prm_TABLE = TableName;
String prm_ALTKEY = ""; // TODO: generate alt-key based on key of table
String prm_COMMENT = Env.getContext(Env.getCtx(), "MigrationScriptComment");
String prm_COMMENT = Env.getContext(Env.getCtx(), I_AD_UserPreference.COLUMNNAME_MigrationScriptComment);
String prm_PROJECT = MSysConfig.getValue(MSysConfig.PROJECT_ID_PROJECT);
return getNextID_HTTP(TableName, website, prm_USER,
@ -1219,7 +1219,11 @@ public class MSequence extends X_AD_Sequence
"T_TRIALBALANCE"
};
private static boolean isExceptionCentralized(String tableName) {
/**
* @param tableName
* @return true if centralized id shouldn't be used for tableName
*/
public static boolean isExceptionCentralized(String tableName) {
for (String exceptionTable : dontUseCentralized) {
if (tableName.equalsIgnoreCase(exceptionTable))
@ -1232,8 +1236,12 @@ public class MSequence extends X_AD_Sequence
private static CCache<String,String> tablesWithEntityType = new CCache<String,String>(Table_Name, "TablesWithEntityType", 60, 0, false, 0);
private synchronized static boolean isTableWithEntityType(String tableName) {
if (tablesWithEntityType == null || tablesWithEntityType.size() == 0) {
/**
* @param tableName
* @return true if tableName has entity type column name
*/
public static synchronized boolean isTableWithEntityType(String tableName) {
if (tablesWithEntityType.size() == 0) {
final String sql = "SELECT TableName FROM AD_Table WHERE AD_Table_ID IN (SELECT AD_Table_ID FROM AD_Column WHERE ColumnName='EntityType') ORDER BY TableName";
List<List<Object>> list = DB.getSQLArrayObjectsEx(null, sql);
for (List<Object> row : list) {

View File

@ -66,7 +66,6 @@ import org.compiere.util.DB;
import org.compiere.util.DisplayType;
import org.compiere.util.Env;
import org.compiere.util.Evaluatee;
import org.compiere.util.Ini;
import org.compiere.util.Language;
import org.compiere.util.Msg;
import org.compiere.util.SecureEngine;
@ -468,6 +467,17 @@ public abstract class PO
return m_idOld;
} // getID
/**
* @return UUID value
*/
public String get_UUID() {
String uidColumn = getUUIDColumnName();
if (p_info.getColumnIndex(uidColumn) >=0)
return get_ValueAsString(uidColumn);
else
return null;
}
/**
* Get Context
* @return context
@ -2630,22 +2640,18 @@ public abstract class PO
return saveFinish (false, ok);
} // saveUpdate
/**
* @return true if sql migration script should be logged for changes to this PO instance
*/
private boolean isLogSQLScript() {
boolean logMigrationScript = false;
if (Ini.isClient()) {
logMigrationScript = Ini.isPropertyBool(Ini.P_LOGMIGRATIONSCRIPT);
} else {
String sysProperty = Env.getCtx().getProperty("LogMigrationScript", "N");
logMigrationScript = "y".equalsIgnoreCase(sysProperty) || "true".equalsIgnoreCase(sysProperty);
}
return logMigrationScript;
return Env.isLogMigrationScript(p_info.getTableName());
}
private boolean doUpdate(boolean withValues) {
//params for insert statement
List<Object> params = new ArrayList<Object>();
String where = get_WhereClause(true);
String where = withValues ? get_WhereClause(true, get_ValueAsString(getUUIDColumnName())) : get_WhereClause(true);
List<Object> optimisticLockingParams = new ArrayList<Object>();
if (is_UseOptimisticLocking() && m_optimisticLockingColumns != null && m_optimisticLockingColumns.length > 0)
@ -2737,6 +2743,55 @@ public abstract class PO
// values
if (value == Null.NULL)
sql.append("NULL");
else if (value instanceof Integer && "Record_ID".equalsIgnoreCase(columnName))
{
Integer idValue = (Integer) value;
if (idValue <= MTable.MAX_OFFICIAL_ID)
{
sql.append(value);
}
else if (p_info.getColumnIndex("AD_Table_ID") >= 0)
{
int tableId = get_ValueAsInt("AD_Table_ID");
if (tableId > 0)
{
MTable refTable = MTable.get(Env.getCtx(), tableId);
String refTableName = refTable.getTableName();
String refKeyColumnName = refTable.getKeyColumns()[0];
String refUUColumnName = MTable.getUUIDColumnName(refTableName);
String refUUValue = DB.getSQLValueString(get_TrxName(), "SELECT " + refUUColumnName + " FROM "
+ refTableName + " WHERE " + refKeyColumnName + "=?", (Integer)value);
sql.append("toRecordId('"+ refTableName + "','" + refUUValue + "')");
}
else
{
sql.append(value);
}
}
else
{
sql.append(value);
}
}
else if (value instanceof Integer && p_info.isColumnLookup(i))
{
Integer idValue = (Integer) value;
if (idValue <= MTable.MAX_OFFICIAL_ID)
{
sql.append(value);
}
else
{
MColumn col = MColumn.get(p_info.getAD_Column_ID(columnName));
String refTableName = col.getReferenceTableName();
MTable refTable = MTable.get(Env.getCtx(), refTableName);
String refKeyColumnName = refTable.getKeyColumns()[0];
String refUUColumnName = MTable.getUUIDColumnName(refTableName);
String refUUValue = DB.getSQLValueString(get_TrxName(), "SELECT " + refUUColumnName + " FROM "
+ refTableName + " WHERE " + refKeyColumnName + "=?", (Integer)value);
sql.append("toRecordId('"+ refTableName + "','" + refUUValue + "')");
}
}
else if (value instanceof Integer || value instanceof BigDecimal)
sql.append(value);
else if (c == Boolean.class)
@ -3038,7 +3093,7 @@ public abstract class PO
{
// Set ID for single key - Multi-Key values need explicitly be set previously
if (m_IDs.length == 1 && p_info.hasKeyColumn()
&& m_KeyColumns[0].endsWith("_ID")) // AD_Language, EntityType
&& m_KeyColumns[0].endsWith("_ID") && (Env.isUseCentralizedId(p_info.getTableName()) || !isLogSQLScript())) // AD_Language, EntityType
{
int no = saveNew_getID();
if (no <= 0)
@ -3172,10 +3227,65 @@ public abstract class PO
{
try
{
if (c == Object.class) // may have need to deal with null values differently
if (m_IDs.length == 1 && p_info.hasKeyColumn()
&& m_KeyColumns[0].endsWith("_ID") && m_KeyColumns[0].equals(p_info.getColumnName(i)) && !Env.isUseCentralizedId(p_info.getTableName()))
{
MSequence sequence = MSequence.get(Env.getCtx(), p_info.getTableName(), get_TrxName(), true);
sqlValues.append("nextidfunc("+sequence.getAD_Sequence_ID()+",'N')");
}
else if (c == Object.class) // may have need to deal with null values differently
sqlValues.append (saveNewSpecial (value, i));
else if (value == null || value.equals (Null.NULL))
sqlValues.append ("NULL");
else if (value instanceof Integer && "Record_ID".equalsIgnoreCase(p_info.getColumnName(i)))
{
Integer idValue = (Integer) value;
if (idValue <= MTable.MAX_OFFICIAL_ID)
{
sqlValues.append(value);
}
else if (p_info.getColumnIndex("AD_Table_ID") >= 0)
{
int tableId = get_ValueAsInt("AD_Table_ID");
if (tableId > 0)
{
MTable refTable = MTable.get(Env.getCtx(), tableId);
String refTableName = refTable.getTableName();
String refKeyColumnName = refTable.getKeyColumns()[0];
String refUUColumnName = MTable.getUUIDColumnName(refTableName);
String refUUValue = DB.getSQLValueString(get_TrxName(), "SELECT " + refUUColumnName + " FROM "
+ refTableName + " WHERE " + refKeyColumnName + "=?", (Integer)value);
sqlValues.append("toRecordId('"+ refTableName + "','" + refUUValue + "')");
}
else
{
sqlValues.append(value);
}
}
else
{
sqlValues.append(value);
}
}
else if (value instanceof Integer && p_info.isColumnLookup(i))
{
Integer idValue = (Integer) value;
if (idValue <= MTable.MAX_OFFICIAL_ID)
{
sqlValues.append(value);
}
else
{
MColumn col = MColumn.get(p_info.getAD_Column_ID(p_info.getColumnName(i)));
String refTableName = col.getReferenceTableName();
MTable refTable = MTable.get(Env.getCtx(), refTableName);
String refKeyColumnName = refTable.getKeyColumns()[0];
String refUUColumnName = MTable.getUUIDColumnName(refTable.getTableName());
String refUUValue = DB.getSQLValueString(get_TrxName(), "SELECT " + refUUColumnName + " FROM "
+ refTableName + " WHERE " + refKeyColumnName + "=?", (Integer)value);
sqlValues.append("toRecordId('"+ refTableName + "','" + refUUValue + "')");
}
}
else if (value instanceof Integer || value instanceof BigDecimal)
sqlValues.append (value);
else if (c == Boolean.class)
@ -3268,6 +3378,8 @@ public abstract class PO
}
}
if (!withValues || Env.isUseCentralizedId(p_info.getTableName()))
{
// Change Log - Only
String insertLog = MSysConfig.getValue(MSysConfig.SYSTEM_INSERT_CHANGELOG, "Y", getAD_Client_ID());
if ( session != null
@ -3288,7 +3400,7 @@ public abstract class PO
if (cLog != null)
AD_ChangeLog_ID = cLog.getAD_ChangeLog_ID();
}
}
}
// Custom Columns
if (m_custom != null)
@ -3336,6 +3448,36 @@ public abstract class PO
boolean ok = no == 1;
if (ok)
{
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()));
m_IDs[0] = Integer.valueOf(id);
set_ValueNoCheck(m_KeyColumns[0], m_IDs[0]);
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))
)
{
// 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);
if (cLog != null)
AD_ChangeLog_ID = cLog.getAD_ChangeLog_ID();
}
}
ok = lobSave();
if (!load(m_trxName)) // re-read Info
{
@ -3666,7 +3808,7 @@ public abstract class PO
}
// The Delete Statement
String where = get_WhereClause(true);
String where = isLogSQLScript() ? get_WhereClause(true, get_ValueAsString(getUUIDColumnName())) : get_WhereClause(true);
List<Object> optimisticLockingParams = new ArrayList<Object>();
if (is_UseOptimisticLocking() && m_optimisticLockingColumns != null && m_optimisticLockingColumns.length > 0)
{
@ -4222,7 +4364,9 @@ public abstract class PO
if (uuidColumn != null && uuidFunction)
sb.append(",").append(PO.getUUIDColumnName(acctTableName));
// .. SELECT
sb.append(") SELECT ").append(get_ID())
sb.append(") SELECT ").append(get_ID() > MTable.MAX_OFFICIAL_ID && Env.isLogMigrationScript(get_TableName())
? "toRecordId("+DB.TO_STRING(get_TableName())+","+DB.TO_STRING(get_UUID())+")"
: get_ID())
.append(", p.C_AcctSchema_ID, p.AD_Client_ID,0,'Y', getDate(),")
.append(getUpdatedBy()).append(",getDate(),").append(getUpdatedBy());
for (int i = 0; i < s_acctColumns.size(); i++)
@ -4231,12 +4375,19 @@ public abstract class PO
sb.append(",generate_uuid()");
// .. FROM
sb.append(" FROM ").append(acctBaseTable)
.append(" p WHERE p.AD_Client_ID=").append(getAD_Client_ID());
.append(" p WHERE p.AD_Client_ID=")
.append(getAD_Client_ID() > MTable.MAX_OFFICIAL_ID && Env.isLogMigrationScript(get_TableName())
? "toRecordId('AD_Client',"+DB.TO_STRING(MClient.get(getAD_Client_ID()).getAD_Client_UU())+")"
: getAD_Client_ID());
if (whereClause != null && whereClause.length() > 0)
sb.append (" AND ").append(whereClause);
sb.append(" AND NOT EXISTS (SELECT * FROM ").append(acctTableName)
.append(" e WHERE e.C_AcctSchema_ID=p.C_AcctSchema_ID AND e.")
.append(get_TableName()).append("_ID=").append(get_ID()).append(")");
.append(get_TableName()).append("_ID=");
if (get_ID() > MTable.MAX_OFFICIAL_ID && Env.isLogMigrationScript(get_TableName()))
sb.append("toRecordId(").append(DB.TO_STRING(get_TableName())).append(",").append(DB.TO_STRING(get_UUID())).append("))");
else
sb.append(get_ID()).append(")");
//
int no = DB.executeUpdate(sb.toString(), get_TrxName());
if (no > 0) {
@ -4304,24 +4455,41 @@ public abstract class PO
else
sb.append(") ");
sb.append("SELECT t.AD_Client_ID, 0, 'Y', getDate(), "+getUpdatedBy()+", getDate(), "+getUpdatedBy()+","
+ "t.AD_Tree_ID, ").append(get_ID()).append(", 0, 999");
+ "t.AD_Tree_ID, ")
.append(get_ID() > MTable.MAX_OFFICIAL_ID && Env.isLogMigrationScript(get_TableName())
? "toRecordId("+DB.TO_STRING(get_TableName())+","+DB.TO_STRING(get_UUID())+")"
: get_ID())
.append(", 0, 999");
if (uuidColumn != null && uuidFunction)
sb.append(", Generate_UUID() ");
else
sb.append(" ");
sb.append("FROM AD_Tree t "
+ "WHERE t.AD_Client_ID=").append(getAD_Client_ID()).append(" AND t.IsActive='Y'");
+ "WHERE t.AD_Client_ID=")
.append(getAD_Client_ID() > MTable.MAX_OFFICIAL_ID && Env.isLogMigrationScript(get_TableName())
? "toRecordId('AD_Client',"+DB.TO_STRING(MClient.get(getAD_Client_ID()).getAD_Client_UU())+")"
: getAD_Client_ID())
.append(" AND t.IsActive='Y'");
// Account Element Value handling
if (C_Element_ID != 0)
sb.append(" AND EXISTS (SELECT * FROM C_Element ae WHERE ae.C_Element_ID=")
.append(C_Element_ID).append(" AND t.AD_Tree_ID=ae.AD_Tree_ID)");
.append(C_Element_ID > MTable.MAX_OFFICIAL_ID && Env.isLogMigrationScript(get_TableName())
? "toRecordId('C_Element',"+DB.TO_STRING(new MElement(getCtx(), C_Element_ID, get_TrxName()).getC_Element_UU())+")"
: C_Element_ID)
.append(" AND t.AD_Tree_ID=ae.AD_Tree_ID)");
else // std trees
sb.append(" AND t.IsAllNodes='Y' AND t.TreeType='").append(treeType).append("'");
if (MTree_Base.TREETYPE_CustomTable.equals(treeType))
sb.append(" AND t.AD_Table_ID=").append(get_Table_ID());
sb.append(" AND t.AD_Table_ID=")
.append(get_Table_ID() > MTable.MAX_OFFICIAL_ID && Env.isLogMigrationScript(get_TableName())
? "toRecordId('AD_Table',"+DB.TO_STRING(MTable.get(get_Table_ID()).getAD_Table_UU())+")"
: get_Table_ID());
// Duplicate Check
sb.append(" AND NOT EXISTS (SELECT * FROM " + MTree_Base.getNodeTableName(treeType) + " e "
+ "WHERE e.AD_Tree_ID=t.AD_Tree_ID AND Node_ID=").append(get_ID()).append(")");
+ "WHERE e.AD_Tree_ID=t.AD_Tree_ID AND Node_ID=")
.append(get_ID() > MTable.MAX_OFFICIAL_ID && Env.isLogMigrationScript(get_TableName())
? "toRecordId("+DB.TO_STRING(get_TableName())+","+DB.TO_STRING(get_UUID())+")"
: get_ID()).append(")");
int no = DB.executeUpdate(sb.toString(), get_TrxName());
if (no > 0) {
if (log.isLoggable(Level.FINE)) log.fine("#" + no + " - TreeType=" + treeType);

View File

@ -47,6 +47,7 @@ import org.adempiere.util.ServerContext;
import org.adempiere.util.ServerContextProvider;
import org.compiere.Adempiere;
import org.compiere.db.CConnection;
import org.compiere.dbPort.Convert;
import org.compiere.model.GridTab;
import org.compiere.model.GridWindowVO;
import org.compiere.model.MClient;
@ -55,6 +56,7 @@ import org.compiere.model.MLookupCache;
import org.compiere.model.MQuery;
import org.compiere.model.MRefList;
import org.compiere.model.MRole;
import org.compiere.model.MSequence;
import org.compiere.model.MSession;
import org.compiere.model.MSysConfig;
import org.compiere.model.MTable;
@ -143,7 +145,6 @@ public final class Env
private final static ContextProvider clientContextProvider = new DefaultContextProvider();
private static List<IEnvEventListener> eventListeners = new ArrayList<IEnvEventListener>();
public static int adWindowDummyID =200054;
@ -2201,4 +2202,51 @@ public final class Env
}
}
/**
* @param tableName
* @return true if log migration script is turn on and should be used for tableName
*/
public static boolean isLogMigrationScript(String tableName) {
boolean logMigrationScript = false;
if (Ini.isClient()) {
logMigrationScript = Ini.isPropertyBool(Ini.P_LOGMIGRATIONSCRIPT);
} else {
String sysProperty = Env.getCtx().getProperty(Ini.P_LOGMIGRATIONSCRIPT, "N");
logMigrationScript = "y".equalsIgnoreCase(sysProperty) || "true".equalsIgnoreCase(sysProperty);
}
return logMigrationScript ? !Convert.isDontLogTable(tableName) : false;
}
/**
* @return true if centralized id is turn on and should be used for tableName
*/
public static boolean isUseCentralizedId(String tableName)
{
String sysProperty = Env.getCtx().getProperty(Ini.P_ADEMPIERESYS, "N");
boolean adempiereSys = "y".equalsIgnoreCase(sysProperty) || "true".equalsIgnoreCase(sysProperty);
if (adempiereSys && Env.getAD_Client_ID(Env.getCtx()) > 11)
adempiereSys = false;
if (adempiereSys)
{
boolean b = MSysConfig.getBooleanValue(MSysConfig.DICTIONARY_ID_USE_CENTRALIZED_ID, true);
if (b)
return !MSequence.isExceptionCentralized(tableName);
else
return b;
}
else
{
boolean queryProjectServer = false;
if (MSequence.isTableWithEntityType(tableName))
queryProjectServer = true;
if (!queryProjectServer && MSequence.Table_Name.equalsIgnoreCase(tableName))
queryProjectServer = true;
if (queryProjectServer && !MSequence.isExceptionCentralized(tableName)) {
return MSysConfig.getBooleanValue(MSysConfig.PROJECT_ID_USE_CENTRALIZED_ID, false);
}
}
return false;
}
} // Env

View File

@ -21,7 +21,9 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
@ -42,12 +44,15 @@ import org.adempiere.webui.window.Dialog;
import org.compiere.model.GridTab;
import org.compiere.model.MRole;
import org.compiere.model.MSysConfig;
import org.compiere.model.MTable;
import org.compiere.model.PO;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.KeyNamePair;
import org.compiere.util.Msg;
import org.compiere.util.NamePair;
import org.compiere.util.Trx;
import org.compiere.util.Util;
import org.zkoss.zk.au.out.AuFocus;
import org.zkoss.zk.ui.event.DropEvent;
@ -701,9 +706,14 @@ public class ADSortTab extends Panel implements IADTabpanel
if (!adWindowPanel.getToolbar().isSaveEnable())
return;
boolean ok = true;
//TODO: should use model instead to enable change log and event handling
StringBuilder info = new StringBuilder();
StringBuffer sql = null;
MTable table = MTable.get(Env.getCtx(), m_TableName);
Map<Integer, ListElement> noModelBackup = new HashMap<>();
Map<Integer, ListElement> yesModelBackup = new HashMap<>();
Trx trx = Trx.get(Trx.createTrxName("ADSortTab_save"), true);
try {
trx.start();
// noList - Set SortColumn to null and optional YesNo Column to 'N'
for (int i = 0; i < noModel.getSize(); i++)
{
@ -713,25 +723,28 @@ public class ADSortTab extends Panel implements IADTabpanel
if(pp.getSortNo() == 0 && (m_ColumnYesNoName == null || !pp.isYes()))
continue; // no changes
//
sql = new StringBuffer();
sql.append("UPDATE ").append(m_TableName)
.append(" SET ").append(m_ColumnSortName).append("=0");
PO po = table.getPO(pp.getKey(), trx.getTrxName());
po.set_ValueOfColumn(m_ColumnSortName, 0);
if (m_ColumnYesNoName != null)
sql.append(",").append(m_ColumnYesNoName).append("='N'");
sql.append(", Updated=getDate(), UpdatedBy=").append(Env.getAD_User_ID(Env.getCtx()));
sql.append(" WHERE ").append(m_KeyColumnName).append("=").append(pp.getKey());
if (DB.executeUpdate(sql.toString(), null) == 1) {
po.set_ValueOfColumn(m_ColumnYesNoName, "N");
try {
po.saveEx();
ListElement backup = new ListElement(pp.getKey(), pp.getName(), pp.getSortNo(), pp.isYes(), pp.getAD_Client_ID(), pp.getAD_Org_ID());
noModelBackup.put(i, backup);
pp.setSortNo(0);
pp.setIsYes(false);
}
else {
} catch (Exception e) {
ok = false;
trx.rollback();
if (info.length() > 0)
info.append(", ");
info.append(pp.getName());
log.log(Level.SEVERE, "NoModel - Not updated: " + m_KeyColumnName + "=" + pp.getKey());
log.log(Level.SEVERE, "NoModel - Not updated: " + m_KeyColumnName + "=" + pp.getKey(), e);
break;
}
}
if (ok) {
// yesList - Set SortColumn to value and optional YesNo Column to 'Y'
int index = 0;
for (int i = 0; i < yesModel.getSize(); i++)
@ -743,25 +756,53 @@ public class ADSortTab extends Panel implements IADTabpanel
if(pp.getSortNo() == index && (m_ColumnYesNoName == null || pp.isYes()))
continue; // no changes
//
sql = new StringBuffer();
sql.append("UPDATE ").append(m_TableName)
.append(" SET ").append(m_ColumnSortName).append("=").append(index);
PO po = table.getPO(pp.getKey(), trx.getTrxName());
po.set_ValueOfColumn(m_ColumnSortName, index);
if (m_ColumnYesNoName != null)
sql.append(",").append(m_ColumnYesNoName).append("='Y'");
sql.append(", Updated=getDate(), UpdatedBy=").append(Env.getAD_User_ID(Env.getCtx()));
sql.append(" WHERE ").append(m_KeyColumnName).append("=").append(pp.getKey());
if (DB.executeUpdate(sql.toString(), null) == 1) {
po.set_ValueOfColumn(m_ColumnYesNoName, "Y");
try {
po.saveEx();
ListElement backup = new ListElement(pp.getKey(), pp.getName(), pp.getSortNo(), pp.isYes(), pp.getAD_Client_ID(), pp.getAD_Org_ID());
yesModelBackup.put(i, backup);
pp.setSortNo(index);
pp.setIsYes(true);
}
else {
} catch (Exception e) {
ok = false;
trx.rollback();
if (info.length() > 0)
info.append(", ");
info.append(pp.getName());
log.log(Level.SEVERE, "YesModel - Not updated: " + m_KeyColumnName + "=" + pp.getKey());
log.log(Level.SEVERE, "YesModel - Not updated: " + m_KeyColumnName + "=" + pp.getKey(), e);
break;
}
}
}
if (ok) {
try {
trx.commit(true);
} catch (Exception e) {
ok = false;
trx.rollback();
info.append("Failed to commit database transaction");
log.log(Level.SEVERE, "Failed to commit database transaction", e);
}
}
if (!ok) {
//rollback changes to yes and no model
for(Integer index : noModelBackup.keySet()) {
ListElement e = noModelBackup.get(index);
noModel.setElementAt(e, index);
}
for(Integer index : yesModelBackup.keySet()) {
ListElement e = yesModelBackup.get(index);
yesModel.setElementAt(e, index);
}
}
} finally {
trx.close();
}
//
if (ok) {
setIsChanged(false);

View File

@ -36,6 +36,7 @@ import org.compiere.model.MUserPreference;
import org.compiere.model.SystemIDs;
import org.compiere.util.CLogger;
import org.compiere.util.Env;
import org.compiere.util.Ini;
import org.compiere.util.Msg;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
@ -136,24 +137,24 @@ public class WPreference extends WQuickEntry implements EventListener<Event>, Va
if (Env.getAD_Client_ID(Env.getCtx()) <= 20 && Env.getAD_User_ID(Env.getCtx()) <= 102) {
this.appendChild(new Space());
adempiereSys = new WYesNoEditor("AdempiereSys", Msg.getMsg(Env.getCtx(), "AdempiereSys", true),
adempiereSys = new WYesNoEditor(Ini.P_ADEMPIERESYS, Msg.getMsg(Env.getCtx(), Ini.P_ADEMPIERESYS, true),
null, false, false, true);
adempiereSys.getComponent().setTooltiptext(Msg.getMsg(Env.getCtx(), "AdempiereSys", false));
adempiereSys.getComponent().setTooltiptext(Msg.getMsg(Env.getCtx(), Ini.P_ADEMPIERESYS, false));
div = new Div();
div.setStyle(LINE_DIV_STYLE);
div.appendChild(adempiereSys.getComponent());
this.appendChild(div);
adempiereSys.setValue(Env.getCtx().getProperty("AdempiereSys"));
adempiereSys.setValue(Env.getCtx().getProperty(Ini.P_ADEMPIERESYS));
adempiereSys.addValueChangeListener(this);
logMigrationScript = new WYesNoEditor("LogMigrationScript", Msg.getMsg(Env.getCtx(), "LogMigrationScript", true),
logMigrationScript = new WYesNoEditor(Ini.P_LOGMIGRATIONSCRIPT, Msg.getMsg(Env.getCtx(), Ini.P_LOGMIGRATIONSCRIPT, true),
null, false, false, true);
logMigrationScript.getComponent().setTooltiptext(Msg.getMsg(Env.getCtx(), "LogMigrationScript", false));
logMigrationScript.getComponent().setTooltiptext(Msg.getMsg(Env.getCtx(), Ini.P_LOGMIGRATIONSCRIPT, false));
div = new Div();
div.setStyle(LINE_DIV_STYLE);
div.appendChild(logMigrationScript.getComponent());
this.appendChild(div);
logMigrationScript.setValue(Env.getCtx().getProperty("LogMigrationScript"));
logMigrationScript.setValue(Env.getCtx().getProperty(Ini.P_LOGMIGRATIONSCRIPT));
logMigrationScript.addValueChangeListener(this);
}
@ -250,12 +251,12 @@ public class WPreference extends WQuickEntry implements EventListener<Event>, Va
// Log Migration Script and AdempiereSys are just in-memory preferences, must not be saved
if (logMigrationScript != null) {
Env.getCtx().setProperty("LogMigrationScript", (Boolean)logMigrationScript.getValue() ? "Y" : "N");
Env.getCtx().setProperty("P|LogMigrationScript", (Boolean)logMigrationScript.getValue() ? "Y" : "N");
Env.getCtx().setProperty(Ini.P_LOGMIGRATIONSCRIPT, (Boolean)logMigrationScript.getValue() ? "Y" : "N");
Env.getCtx().setProperty("P|"+Ini.P_LOGMIGRATIONSCRIPT, (Boolean)logMigrationScript.getValue() ? "Y" : "N");
}
if (adempiereSys != null) {
Env.getCtx().setProperty("AdempiereSys", (Boolean)adempiereSys.getValue() ? "Y" : "N");
Env.getCtx().setProperty("P|AdempiereSys", (Boolean)adempiereSys.getValue() ? "Y" : "N");
Env.getCtx().setProperty(Ini.P_ADEMPIERESYS, (Boolean)adempiereSys.getValue() ? "Y" : "N");
Env.getCtx().setProperty("P|"+Ini.P_ADEMPIERESYS, (Boolean)adempiereSys.getValue() ? "Y" : "N");
}
this.detach();
@ -265,12 +266,12 @@ public class WPreference extends WQuickEntry implements EventListener<Event>, Va
if (evt.getSource() instanceof WYesNoEditor) {
// Log Migration Script and AdempiereSys are just in-memory preferences, set them without need to save
if (evt.getSource() == logMigrationScript) {
Env.getCtx().setProperty("LogMigrationScript", (Boolean)logMigrationScript.getValue() ? "Y" : "N");
Env.getCtx().setProperty("P|LogMigrationScript", (Boolean)logMigrationScript.getValue() ? "Y" : "N");
Env.getCtx().setProperty(Ini.P_LOGMIGRATIONSCRIPT, (Boolean)logMigrationScript.getValue() ? "Y" : "N");
Env.getCtx().setProperty("P|"+Ini.P_LOGMIGRATIONSCRIPT, (Boolean)logMigrationScript.getValue() ? "Y" : "N");
dynamicDisplay();
} else if (evt.getSource() == adempiereSys) {
Env.getCtx().setProperty("AdempiereSys", (Boolean)adempiereSys.getValue() ? "Y" : "N");
Env.getCtx().setProperty("P|AdempiereSys", (Boolean)adempiereSys.getValue() ? "Y" : "N");
Env.getCtx().setProperty(Ini.P_ADEMPIERESYS, (Boolean)adempiereSys.getValue() ? "Y" : "N");
Env.getCtx().setProperty("P|"+Ini.P_ADEMPIERESYS, (Boolean)adempiereSys.getValue() ? "Y" : "N");
}
}
super.valueChange(evt);

View File

@ -32,20 +32,29 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Properties;
import org.adempiere.exceptions.DBException;
import org.compiere.dbPort.Convert;
import org.compiere.model.I_AD_UserPreference;
import org.compiere.model.MAcctSchema;
import org.compiere.model.MBPartner;
import org.compiere.model.MClient;
import org.compiere.model.MMessage;
import org.compiere.model.MProduct;
import org.compiere.model.MProductCategory;
import org.compiere.model.MProductCategoryAcct;
import org.compiere.model.MTest;
import org.compiere.model.POInfo;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.Ini;
import org.compiere.util.Trx;
import org.idempiere.test.AbstractTestCase;
import org.idempiere.test.DictionaryIDs;
import org.junit.jupiter.api.Test;
/**
@ -480,4 +489,56 @@ public class POTest extends AbstractTestCase
assertEquals(expected, testPo.getTestVirtualQty().setScale(2, RoundingMode.HALF_UP), "Wrong value returned");
}
@Test
public void testLogMigrationScript() {
MClient client = MClient.get(Env.getCtx());
MAcctSchema as = client.getAcctSchema();
assertFalse(Env.isLogMigrationScript(MProduct.Table_Name), "Unexpected Log Migration Script default for MProduct");
Env.getCtx().setProperty(Ini.P_LOGMIGRATIONSCRIPT, "Y");
Env.setContext(Env.getCtx(), I_AD_UserPreference.COLUMNNAME_MigrationScriptComment, "testLogMigrationScript");
assertTrue(Env.isLogMigrationScript(MProduct.Table_Name), "Unexpected Log Migration Script Y/N value for MProduct");
String fileName = Convert.getMigrationScriptFileName("testLogMigrationScript");
String folderPg = Convert.getMigrationScriptFolder("postgresql");
String folderOr = Convert.getMigrationScriptFolder("oracle");
MProductCategory lotLevel = new MProductCategory(Env.getCtx(), 0, null);
lotLevel.setName("testLogMigrationScript");
lotLevel.saveEx();
MProduct product = null;
try {
MProductCategoryAcct lotLevelAcct = MProductCategoryAcct.get(lotLevel.get_ID(), as.get_ID());
lotLevelAcct = new MProductCategoryAcct(Env.getCtx(), lotLevelAcct);
lotLevelAcct.setCostingLevel(MAcctSchema.COSTINGLEVEL_BatchLot);
lotLevelAcct.saveEx();
product = new MProduct(Env.getCtx(), 0, null);
product.setM_Product_Category_ID(lotLevel.get_ID());
product.setName("testLogMigrationScript");
product.setProductType(MProduct.PRODUCTTYPE_Item);
product.setIsStocked(true);
product.setIsSold(true);
product.setIsPurchased(true);
product.setC_UOM_ID(DictionaryIDs.C_UOM.EACH.id);
product.setC_TaxCategory_ID(DictionaryIDs.C_TaxCategory.STANDARD.id);
product.setM_AttributeSet_ID(DictionaryIDs.M_AttributeSet.FERTILIZER_LOT.id);
product.saveEx();
} finally {
rollback();
if (product != null) {
product.set_TrxName(null);
product.deleteEx(true);
}
lotLevel.deleteEx(true);
}
File file = new File(folderPg + fileName);
assertTrue(file.exists(), "Not found: " + folderPg + fileName);
file.delete();
file = new File(folderOr + fileName);
assertTrue(file.exists(), "Not found: " + folderOr + fileName);
file.delete();
}
}