diff --git a/.gitignore b/.gitignore index 024a9ebc416..3f6fcf83f31 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,12 @@ **/.settings/ *.cache *.diff -*.project -*.classpath +**/.classpath +**/.project + +**/activemq-data/ +**/data/ +**/log/ de.metas.endcustomer.mf15/metasfresh.properties /de.metas.endcustomer.mf15/de.metas.endcustomer.mf15.swingui/log/ diff --git a/de.metas.acct.base/src/main/java-legacy/org/compiere/acct/Doc_MatchInv.java b/de.metas.acct.base/src/main/java-legacy/org/compiere/acct/Doc_MatchInv.java index b0b49c497a9..7c1eb9857f6 100644 --- a/de.metas.acct.base/src/main/java-legacy/org/compiere/acct/Doc_MatchInv.java +++ b/de.metas.acct.base/src/main/java-legacy/org/compiere/acct/Doc_MatchInv.java @@ -239,8 +239,10 @@ public List createFacts(final MAcctSchema as) // dr.setLocationFromLocator(m_receiptLine.getM_Locator_ID(), false); // to Loc // Set AmtAcctCr/Dr from Receipt (sets also Project) if (!dr.updateReverseLine(I_M_InOut.Table_ID, // Amt updated - m_receiptLine.getM_InOut_ID(), m_receiptLine.getM_InOutLine_ID(), - receiptQtyMultiplier)) + m_receiptLine.getM_InOut_ID(), + m_receiptLine.getM_InOutLine_ID(), + receiptQtyMultiplier) + ) { throw newPostingException() .setC_AcctSchema(as) diff --git a/de.metas.adempiere.adempiere/base/src/main/java-legacy/org/compiere/util/Env.java b/de.metas.adempiere.adempiere/base/src/main/java-legacy/org/compiere/util/Env.java index 1667f1989ee..b17f1602013 100644 --- a/de.metas.adempiere.adempiere/base/src/main/java-legacy/org/compiere/util/Env.java +++ b/de.metas.adempiere.adempiere/base/src/main/java-legacy/org/compiere/util/Env.java @@ -24,6 +24,7 @@ import java.sql.Timestamp; import java.util.ArrayList; import java.util.Date; +import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Properties; @@ -58,7 +59,6 @@ import org.compiere.model.MLanguage; import org.compiere.swing.CFrame; import org.slf4j.Logger; -import org.springframework.util.CollectionUtils; import com.google.common.base.Supplier; @@ -390,7 +390,25 @@ public static final Properties copyCtx(final Properties ctx) Check.assumeNotNull(ctx, "ctx not null"); final Properties newCtx = new Properties(); - CollectionUtils.mergePropertiesIntoMap(ctx, newCtx); + + // we can't use this great tool, because it (reasonably) assumes that the given ctx doews not have null values + // org.springframework.util.CollectionUtils.mergePropertiesIntoMap(ctx, newCtx); + + for (final Enumeration en = ctx.propertyNames(); en.hasMoreElements();) + { + final String key = (String)en.nextElement(); + Object value = ctx.get(key); + if (value == null) + { + // Allow for defaults fallback or potentially overridden accessor + value = newCtx.getProperty(key); + } + if (value == null) + { + continue; // the given ctx might have null values, so this chack is crucial + } + newCtx.put(key, value); + } return newCtx; } @@ -1180,10 +1198,10 @@ public static int getAD_Role_ID(Properties ctx) return Env.getContextAsInt(ctx, CTXNAME_AD_Role_ID); } // getAD_Role_ID -// public static void setAD_Role_ID(Properties ctx, final int adRoleId) -// { -// Env.setContext(ctx, CTXNAME_AD_Role_ID, adRoleId); -// } // getAD_Role_ID + // public static void setAD_Role_ID(Properties ctx, final int adRoleId) + // { + // Env.setContext(ctx, CTXNAME_AD_Role_ID, adRoleId); + // } // getAD_Role_ID public static IUserRolePermissions getUserRolePermissions() { @@ -1208,7 +1226,6 @@ public static IUserRolePermissions getUserRolePermissions(final String permissio return Services.get(IUserRolePermissionsDAO.class).retrieveUserRolePermissions(userRolePermissionsKey); } - public static void resetUserRolePermissions() { Services.get(IUserRolePermissionsDAO.class).resetCache(); @@ -1437,7 +1454,7 @@ public static void verifyLanguage(final Language language) // // Check if we have a perfect match - if(AD_Languages.contains(searchAD_Language)) + if (AD_Languages.contains(searchAD_Language)) { return; } @@ -1614,11 +1631,10 @@ public static String parseContext(Properties ctx, int WindowNo, IStringExpressio return parseContext(ctx, WindowNo, expression, onlyWindow, ignoreUnparsable); } // parseContext - /*************************************************************************/ // Array of active Windows - private static ArrayList s_windows = new ArrayList(20); + private static ArrayList s_windows = new ArrayList<>(20); /** * Add Container and return WindowNo. The container is a APanel, AWindow or JFrame/JDialog @@ -1845,7 +1861,7 @@ public static boolean isWindows() } // isWindows /** Array of hidden Windows */ - private static ArrayList s_hiddenWindows = new ArrayList(); + private static ArrayList s_hiddenWindows = new ArrayList<>(); /** Closing Window Indicator */ private static boolean s_closingWindows = false; @@ -1962,7 +1978,7 @@ public static void sleep(final int sec) */ public static Set updateUI() { - Set updated = new HashSet(); + Set updated = new HashSet<>(); for (Container c : s_windows) { Window w = getFrame(c); diff --git a/de.metas.adempiere.adempiere/base/src/main/java/org/adempiere/ad/dao/impl/InSubQueryFilter.java b/de.metas.adempiere.adempiere/base/src/main/java/org/adempiere/ad/dao/impl/InSubQueryFilter.java index 0fdb025d635..1adf2d43d22 100644 --- a/de.metas.adempiere.adempiere/base/src/main/java/org/adempiere/ad/dao/impl/InSubQueryFilter.java +++ b/de.metas.adempiere.adempiere/base/src/main/java/org/adempiere/ad/dao/impl/InSubQueryFilter.java @@ -10,12 +10,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -44,9 +44,9 @@ /** * Filters out only records which are present in sub-query. - * + * * @author tsa - * + * * @param */ public class InSubQueryFilter implements IQueryFilter, ISqlQueryFilter @@ -66,7 +66,7 @@ public class InSubQueryFilter implements IQueryFilter, ISqlQueryFilter private static final transient Logger logger = LogManager.getLogger(InSubQueryFilter.class); /** - * + * * @param columnName this query match column * @param subQueryColumnName sub query match column * @param subQuery sub query @@ -132,7 +132,7 @@ private final void buildSql() } final TypedSqlQuery subQueryImpl = TypedSqlQuery.cast(subQuery); - + // // Decide if we will render the SQL using "EXISTS (...)" (preferred option, at least of postresql) or "IN (...)". final boolean useIN; @@ -142,7 +142,7 @@ private final void buildSql() // In case the sub query is done on the same table as the parent table, we can't write it with "EXISTS" // Because we don't have aliases. // Therefore, in such cases, we have to keep the writing with "IN" - logDevelopmentWarn("The query has to be written with IN instead of EXISTS because the tablename is the same for both query and sub query."); + //logDevelopmentWarn("The query has to be written with IN instead of EXISTS because the tablename is the same for both query and sub query."); useIN = true; } else if (subQueryImpl.hasLimitOrOffset()) @@ -178,9 +178,9 @@ else if (subQueryImpl.hasLimitOrOffset()) /** * Build the filter SQL using EXISTS. - * + * * e.g. EXISTS (SELECT 1 FROM SubTable WHERE ParentTable.JoinColumn=SubTable.JoinColumn AND .....) - * + * * @param subQueryImpl * @return sql */ @@ -189,7 +189,7 @@ private String buildSql_UsingEXISTS(final TypedSqlQuery subQueryImpl) final String subQueryColumnNameWithModifier = modifier.getColumnSql(this.subQueryColumnName); // - // Build the new sub-query's SELECT FROM + // Build the new sub-query's SELECT FROM final StringBuilder subQuerySelectClause = new StringBuilder() .append("SELECT 1 FROM ").append(subQueryImpl.getTableName()); final boolean subQueryUseOrderByClause = false; @@ -232,9 +232,9 @@ private String buildSql_UsingEXISTS(final TypedSqlQuery subQueryImpl) /** * Build the filter SQL using IN. - * + * * e.g. ParentTable.JoinColumn IN (SELECT 1 FROM SubTable WHERE ...) - * + * * @param subQueryImpl * @return sql */ @@ -243,7 +243,7 @@ private String buildSql_UsingIN(final TypedSqlQuery subQueryImpl) final String subQueryColumnNameWithModifier = modifier.getColumnSql(this.subQueryColumnName); // - // Build the new sub-query's SELECT FROM + // Build the new sub-query's SELECT FROM final StringBuilder subQuerySelectClause = new StringBuilder() .append("SELECT ").append(subQueryColumnNameWithModifier) .append(" FROM ").append(subQueryImpl.getTableName()); @@ -279,7 +279,7 @@ private String buildSql_UsingIN(final TypedSqlQuery subQueryImpl) .append(")") .toString(); } - + private final void logDevelopmentWarn(final String message) { if (Services.get(IDeveloperModeBL.class).isEnabled()) @@ -322,7 +322,7 @@ private List getSubQueryValues(final T model) final List subQueryResult = subQuery.list(); - final List subQueryValues = new ArrayList(subQueryResult.size()); + final List subQueryValues = new ArrayList<>(subQueryResult.size()); for (Object subModel : subQueryResult) { final Object value0 = InterfaceWrapperHelper.getValue(subModel, this.subQueryColumnName).orNull(); diff --git a/de.metas.adempiere.adempiere/base/src/main/java/org/adempiere/ad/persistence/TableModelLoader.java b/de.metas.adempiere.adempiere/base/src/main/java/org/adempiere/ad/persistence/TableModelLoader.java index 864c65a61c4..77200016527 100644 --- a/de.metas.adempiere.adempiere/base/src/main/java/org/adempiere/ad/persistence/TableModelLoader.java +++ b/de.metas.adempiere.adempiere/base/src/main/java/org/adempiere/ad/persistence/TableModelLoader.java @@ -331,7 +331,7 @@ public final ModelType retrieveModel(final Properties ctx, final Str return model; } } - + public void invalidateCache(final String tableName, final int recordId, final String trxName) { final IModelCacheService modelCacheService = Services.get(IModelCacheService.class); diff --git a/de.metas.adempiere.adempiere/base/src/main/java/org/adempiere/model/InterfaceWrapperHelper.java b/de.metas.adempiere.adempiere/base/src/main/java/org/adempiere/model/InterfaceWrapperHelper.java index 52c3c36892f..27e8a25649e 100644 --- a/de.metas.adempiere.adempiere/base/src/main/java/org/adempiere/model/InterfaceWrapperHelper.java +++ b/de.metas.adempiere.adempiere/base/src/main/java/org/adempiere/model/InterfaceWrapperHelper.java @@ -194,7 +194,7 @@ public static T newInstance(final Class cl) * * @param model the underlying {@link PO}, {@link GridTab} or POJO for which we need an instance of cl * @param cl the interface we need an instance of - * @return and instance of cl which actually wraps model or null if model was null + * @return an instance of cl which actually wraps model or null if model was null */ public static T create(final Object model, final Class cl) { @@ -315,7 +315,7 @@ public static T create(final Properties ctx, final String tableName, final i /** * Loads given model, out of transaction. * NOTE: to be used, mainly for loading master data models. - * + * * @param id model's ID * @param modelClass * @return loaded model @@ -324,10 +324,10 @@ public static T loadOutOfTrx(final int id, final Class modelClass) { return create(Env.getCtx(), id, modelClass, ITrx.TRXNAME_None); } - + /** * Loads given model, using thread inherited transaction. - * + * * @param id model's ID * @param modelClass * @return loaded model @@ -770,7 +770,7 @@ public static String getTableNameOrNull(final Class clazz) * If the modelClass does not have a table name it will return expectedTableName if that's not null. * If the modelClass has a table name but it's not matching the expectedTableName (if not null) an exception will be thrown. * If the modelClass does not hava a table name and expectedTableName is null an exception will be thrown. - * + * * @param modelClass * @param expectedTableName * @return model table name; never returns null diff --git a/de.metas.adempiere.adempiere/migration/src/main/sql/postgresql/system/12-de.metas.event/5461310_sys_gh523-metasfresh_X_EventStoreTemplate.sql b/de.metas.adempiere.adempiere/migration/src/main/sql/postgresql/system/12-de.metas.event/5461310_sys_gh523-metasfresh_X_EventStoreTemplate.sql new file mode 100644 index 00000000000..26506304ffa --- /dev/null +++ b/de.metas.adempiere.adempiere/migration/src/main/sql/postgresql/system/12-de.metas.event/5461310_sys_gh523-metasfresh_X_EventStoreTemplate.sql @@ -0,0 +1,200 @@ + +-- 2017-05-02T15:39:12.336 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Table (AccessLevel,ACTriggerLength,AD_Client_ID,AD_Org_ID,AD_Table_ID,CopyColumnsFromTable,Created,CreatedBy,EntityType,ImportTable,IsActive,IsAutocomplete,IsChangeLog,IsDeleteable,IsDLM,IsHighVolume,IsSecurityEnabled,IsView,LoadSeq,Name,ReplicationType,TableName,Updated,UpdatedBy) VALUES ('4',0,0,0,540812,'N',TO_TIMESTAMP('2017-05-02 15:39:12','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.event','N','Y','N','N','Y','N','Y','N','N',0,'EventStore Template','L','X_EventStoreTemplate',TO_TIMESTAMP('2017-05-02 15:39:12','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-02T15:39:12.340 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Table_Trl (AD_Language,AD_Table_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Table_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Table t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Table_ID=540812 AND NOT EXISTS (SELECT * FROM AD_Table_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Table_ID=t.AD_Table_ID) +; + +-- 2017-05-02T15:39:23.260 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556545,102,0,19,540812,'AD_Client_ID',TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100,'Mandant für diese Installation.','de.metas.event',10,'Ein Mandant ist eine Firma oder eine juristische Person. Sie können keine Daten über Mandanten hinweg verwenden. .','Y','N','N','N','N','Y','N','N','Y','N','N','Mandant',0,TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:39:23.261 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556545 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:39:23.342 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556546,113,0,19,540812,'AD_Org_ID',TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100,'Organisatorische Einheit des Mandanten','de.metas.event',10,'Eine Organisation ist ein Bereich ihres Mandanten - z.B. Laden oder Abteilung. Sie können Daten über Organisationen hinweg gemeinsam verwenden.','Y','N','N','N','N','Y','N','N','Y','N','N','Sektion',0,TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:39:23.343 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556546 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:39:23.423 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556547,245,0,16,540812,'Created',TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100,'Datum, an dem dieser Eintrag erstellt wurde','de.metas.event',29,'Das Feld Erstellt zeigt an, zu welchem Datum dieser Eintrag erstellt wurde.','Y','N','N','N','N','Y','N','N','Y','N','N','Erstellt',0,TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:39:23.424 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556547 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:39:23.506 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Reference_Value_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556548,246,0,18,110,540812,'CreatedBy',TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100,'Nutzer, der diesen Eintrag erstellt hat','de.metas.event',10,'Das Feld Erstellt durch zeigt an, welcher Nutzer diesen Eintrag erstellt hat.','Y','N','N','N','N','Y','N','N','Y','N','N','Erstellt durch',0,TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:39:23.508 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556548 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:39:23.588 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556549,348,0,20,540812,'IsActive',TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100,'Der Eintrag ist im System aktiv','de.metas.event',1,'Es gibt zwei Möglichkeiten, einen Datensatz nicht mehr verfügbar zu machen: einer ist, ihn zu löschen; der andere, ihn zu deaktivieren. Ein deaktivierter Eintrag ist nicht mehr für eine Auswahl verfügbar, aber verfügbar für die Verwendung in Berichten. Es gibt zwei Gründe, Datensätze zu deaktivieren und nicht zu löschen: (1) Das System braucht den Datensatz für Revisionszwecke. (2) Der Datensatz wird von anderen Datensätzen referenziert. Z.B. können Sie keinen Geschäftspartner löschen, wenn es Rechnungen für diesen Geschäftspartner gibt. Sie deaktivieren den Geschäftspartner und verhindern, dass dieser Eintrag in zukünftigen Vorgängen verwendet wird.','Y','N','N','N','N','Y','N','N','Y','N','Y','Aktiv',0,TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:39:23.589 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556549 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:39:23.671 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556550,607,0,16,540812,'Updated',TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100,'Datum, an dem dieser Eintrag aktualisiert wurde','de.metas.event',29,'Aktualisiert zeigt an, wann dieser Eintrag aktualisiert wurde.','Y','N','N','N','N','Y','N','N','Y','N','N','Aktualisiert',0,TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:39:23.672 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556550 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:39:23.752 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Reference_Value_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556551,608,0,18,110,540812,'UpdatedBy',TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100,'Nutzer, der diesen Eintrag aktualisiert hat','de.metas.event',10,'Aktualisiert durch zeigt an, welcher Nutzer diesen Eintrag aktualisiert hat.','Y','N','N','N','N','Y','N','N','Y','N','N','Aktualisiert durch',0,TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:39:23.753 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556551 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:39:23.833 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Element (AD_Client_ID,AD_Element_ID,AD_Org_ID,ColumnName,Created,CreatedBy,EntityType,IsActive,Name,PrintName,Updated,UpdatedBy) VALUES (0,543323,0,'X_EventStoreTemplate_ID',TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.event','Y','EventStore Template','EventStore Template',TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-02T15:39:23.834 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Element_Trl (AD_Language,AD_Element_ID, Description,Help,Name,PO_Description,PO_Help,PO_Name,PO_PrintName,PrintName, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Element_ID, t.Description,t.Help,t.Name,t.PO_Description,t.PO_Help,t.PO_Name,t.PO_PrintName,t.PrintName, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Element t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Element_ID=543323 AND NOT EXISTS (SELECT * FROM AD_Element_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Element_ID=t.AD_Element_ID) +; + +-- 2017-05-02T15:39:23.912 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,EntityType,FieldLength,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556552,543323,0,13,540812,'X_EventStoreTemplate_ID',TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.event',10,'Y','N','N','N','Y','Y','N','N','Y','N','N','EventStore Template',0,TO_TIMESTAMP('2017-05-02 15:39:23','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:39:23.913 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556552 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:39:51.784 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,AllowZoomTo,ColumnName,Created,CreatedBy,DDL_NoForeignKey,DefaultValue,Description,EntityType,FieldLength,Help,IsActive,IsAdvancedText,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsCalculated,IsDimension,IsDLMPartitionBoundary,IsEncrypted,IsGenericZoomKeyColumn,IsGenericZoomOrigin,IsIdentifier,IsKey,IsLazyLoading,IsMandatory,IsParent,IsSelectionColumn,IsStaleable,IsSyncDatabase,IsTranslated,IsUpdateable,IsUseDocSequence,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556553,1047,0,20,540812,'N','Processed',TO_TIMESTAMP('2017-05-02 15:39:51','YYYY-MM-DD HH24:MI:SS'),100,'N','N','Checkbox sagt aus, ob der Beleg verarbeitet wurde. ','de.metas.event',1,'Verarbeitete Belege dürfen in der Regel nich mehr geändert werden.','Y','N','Y','N','N','N','N','N','N','N','N','N','N','N','Y','N','N','N','N','N','Y','N','Verarbeitet',0,TO_TIMESTAMP('2017-05-02 15:39:51','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:39:51.787 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556553 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:41:41.680 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Element (AD_Client_ID,AD_Element_ID,AD_Org_ID,ColumnName,Created,CreatedBy,EntityType,IsActive,Name,PrintName,Updated,UpdatedBy) VALUES (0,543324,0,'EventTime',TO_TIMESTAMP('2017-05-02 15:41:41','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.event','Y','Zeitpunkt','Zeitpunkt',TO_TIMESTAMP('2017-05-02 15:41:41','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-02T15:41:41.684 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Element_Trl (AD_Language,AD_Element_ID, Description,Help,Name,PO_Description,PO_Help,PO_Name,PO_PrintName,PrintName, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Element_ID, t.Description,t.Help,t.Name,t.PO_Description,t.PO_Help,t.PO_Name,t.PO_PrintName,t.PrintName, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Element t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Element_ID=543324 AND NOT EXISTS (SELECT * FROM AD_Element_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Element_ID=t.AD_Element_ID) +; + +-- 2017-05-02T15:42:04.989 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,AllowZoomTo,ColumnName,Created,CreatedBy,DDL_NoForeignKey,EntityType,FieldLength,IsActive,IsAdvancedText,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsCalculated,IsDimension,IsDLMPartitionBoundary,IsEncrypted,IsGenericZoomKeyColumn,IsGenericZoomOrigin,IsIdentifier,IsKey,IsLazyLoading,IsMandatory,IsParent,IsSelectionColumn,IsStaleable,IsSyncDatabase,IsTranslated,IsUpdateable,IsUseDocSequence,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556555,543324,0,16,540812,'N','EventTime',TO_TIMESTAMP('2017-05-02 15:42:04','YYYY-MM-DD HH24:MI:SS'),100,'N','de.metas.event',7,'Y','N','Y','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','Y','N','Zeitpunkt',0,TO_TIMESTAMP('2017-05-02 15:42:04','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:42:04.991 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556555 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:42:08.602 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Column SET IsMandatory='Y',Updated=TO_TIMESTAMP('2017-05-02 15:42:08','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=556555 +; + +-- 2017-05-02T15:44:56.256 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Element (AD_Client_ID,AD_Element_ID,AD_Org_ID,ColumnName,Created,CreatedBy,EntityType,IsActive,Name,PrintName,Updated,UpdatedBy) VALUES (0,543325,0,'EventData',TO_TIMESTAMP('2017-05-02 15:44:56','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.event','Y','Daten','Daten',TO_TIMESTAMP('2017-05-02 15:44:56','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-02T15:44:56.261 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Element_Trl (AD_Language,AD_Element_ID, Description,Help,Name,PO_Description,PO_Help,PO_Name,PO_PrintName,PrintName, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Element_ID, t.Description,t.Help,t.Name,t.PO_Description,t.PO_Help,t.PO_Name,t.PO_PrintName,t.PrintName, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Element t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Element_ID=543325 AND NOT EXISTS (SELECT * FROM AD_Element_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Element_ID=t.AD_Element_ID) +; + +-- 2017-05-02T15:45:49.402 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,AllowZoomTo,ColumnName,Created,CreatedBy,DDL_NoForeignKey,EntityType,FieldLength,IsActive,IsAdvancedText,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsCalculated,IsDimension,IsDLMPartitionBoundary,IsEncrypted,IsGenericZoomKeyColumn,IsGenericZoomOrigin,IsIdentifier,IsKey,IsLazyLoading,IsMandatory,IsParent,IsSelectionColumn,IsStaleable,IsSyncDatabase,IsTranslated,IsUpdateable,IsUseDocSequence,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556556,543325,0,36,540812,'N','EventData',TO_TIMESTAMP('2017-05-02 15:45:49','YYYY-MM-DD HH24:MI:SS'),100,'N','de.metas.event',100000,'Y','N','Y','N','N','N','N','N','N','N','N','N','N','N','Y','N','N','N','N','N','Y','N','Daten',0,TO_TIMESTAMP('2017-05-02 15:45:49','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:45:49.403 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556556 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:46:01.264 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Column SET IsUpdateable='N',Updated=TO_TIMESTAMP('2017-05-02 15:46:01','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=556553 +; + +-- 2017-05-02T15:46:01.705 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Column SET IsUpdateable='N',Updated=TO_TIMESTAMP('2017-05-02 15:46:01','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=556555 +; + +-- 2017-05-02T15:46:02.736 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Column SET IsUpdateable='N',Updated=TO_TIMESTAMP('2017-05-02 15:46:02','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=556556 +; + +-- 2017-05-02T15:46:11.786 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Column SET IsUpdateable='N',Updated=TO_TIMESTAMP('2017-05-02 15:46:11','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=556549 +; + +-- 2017-05-02T15:57:51.070 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,AllowZoomTo,ColumnName,Created,CreatedBy,DDL_NoForeignKey,Description,EntityType,FieldLength,Help,IsActive,IsAdvancedText,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsCalculated,IsDimension,IsDLMPartitionBoundary,IsEncrypted,IsGenericZoomKeyColumn,IsGenericZoomOrigin,IsIdentifier,IsKey,IsLazyLoading,IsMandatory,IsParent,IsSelectionColumn,IsStaleable,IsSyncDatabase,IsTranslated,IsUpdateable,IsUseDocSequence,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556569,2887,0,30,540812,'N','AD_Issue_ID',TO_TIMESTAMP('2017-05-02 15:57:50','YYYY-MM-DD HH24:MI:SS'),100,'N','Automatically created or manually entered System Issue','de.metas.event',10,'System Issues are created to speed up the resolution of any system related issues (potential bugs). If enabled, they are automatically reported to Adempiere. No data or confidential information is transferred.','Y','N','Y','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','Y','N','System-Problem',0,TO_TIMESTAMP('2017-05-02 15:57:50','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:57:51.072 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556569 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:57:55.855 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Column SET DDL_NoForeignKey='Y',Updated=TO_TIMESTAMP('2017-05-02 15:57:55','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=556569 +; + +-- 2017-05-02T17:02:35.879 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,AllowZoomTo,ColumnName,Created,CreatedBy,DDL_NoForeignKey,EntityType,FieldLength,IsActive,IsAdvancedText,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsCalculated,IsDimension,IsDLMPartitionBoundary,IsEncrypted,IsGenericZoomKeyColumn,IsGenericZoomOrigin,IsIdentifier,IsKey,IsLazyLoading,IsMandatory,IsParent,IsSelectionColumn,IsStaleable,IsSyncDatabase,IsTranslated,IsUpdateable,IsUseDocSequence,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556570,543074,0,10,540812,'N','Event_UUID',TO_TIMESTAMP('2017-05-02 17:02:35','YYYY-MM-DD HH24:MI:SS'),100,'N','de.metas.event',60,'Y','N','Y','N','N','N','N','N','N','N','N','N','N','N','Y','N','N','N','N','N','N','N','Event UUID',0,TO_TIMESTAMP('2017-05-02 17:02:35','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T17:02:35.881 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556570 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; diff --git a/de.metas.adempiere.libero.libero/src/main/java/org/eevolution/LiberoConfiguration.java b/de.metas.adempiere.libero.libero/src/main/java/org/eevolution/LiberoConfiguration.java index f2a7e0e24f3..fc263682979 100644 --- a/de.metas.adempiere.libero.libero/src/main/java/org/eevolution/LiberoConfiguration.java +++ b/de.metas.adempiere.libero.libero/src/main/java/org/eevolution/LiberoConfiguration.java @@ -33,7 +33,7 @@ LiberoConfiguration.class, // scan the classes in *this* package and its subpackages MaterialPlanningConfiguration.class, // scan the classes in the material planning sub-packages for components. Without this, we need to have @Bean annotated methods in here MaterialEventConfiguration.class, - StartupListener.class + StartupListener.class // needed when we call this case from a junit test }) public class LiberoConfiguration { diff --git a/de.metas.adempiere.libero.libero/src/main/java/org/eevolution/event/MaterialDocumentListener.java b/de.metas.adempiere.libero.libero/src/main/java/org/eevolution/event/MaterialDocumentListener.java index 98fb6956e20..62535d2c86b 100644 --- a/de.metas.adempiere.libero.libero/src/main/java/org/eevolution/event/MaterialDocumentListener.java +++ b/de.metas.adempiere.libero.libero/src/main/java/org/eevolution/event/MaterialDocumentListener.java @@ -20,7 +20,7 @@ import de.metas.material.event.MaterialDemandEvent; import de.metas.material.event.MaterialEvent; import de.metas.material.event.MaterialEventListener; -import de.metas.material.event.ProductionOrderRequested; +import de.metas.material.event.PPOrderRequestedEvent; import de.metas.material.event.pporder.PPOrder; import lombok.NonNull; @@ -66,14 +66,16 @@ public MaterialDocumentListener(@NonNull final PPOrderProducer ppOrderProducer) @Override public void onEvent(final MaterialEvent event) { - if (!(event instanceof ProductionOrderRequested)) + if (!(event instanceof PPOrderRequestedEvent)) { return; } logger.info("Received event {}", event); - final ProductionOrderRequested productionOrderEvent = (ProductionOrderRequested)event; - createProductionOrderInTrx(productionOrderEvent.getPpOrder(), Date.from(productionOrderEvent.getWhen())); + final PPOrderRequestedEvent productionOrderEvent = (PPOrderRequestedEvent)event; + createProductionOrderInTrx( + productionOrderEvent.getPpOrder(), + Date.from(productionOrderEvent.getEventDescr().getWhen())); } private I_PP_Order createProductionOrderInTrx( diff --git a/de.metas.adempiere.libero.libero/src/main/java/org/eevolution/model/LiberoValidator.java b/de.metas.adempiere.libero.libero/src/main/java/org/eevolution/model/LiberoValidator.java index 01be0964518..a82070d4915 100644 --- a/de.metas.adempiere.libero.libero/src/main/java/org/eevolution/model/LiberoValidator.java +++ b/de.metas.adempiere.libero.libero/src/main/java/org/eevolution/model/LiberoValidator.java @@ -10,36 +10,42 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public - * License along with this program. If not, see + * License along with this program. If not, see * . * #L% */ - import org.adempiere.ad.callout.spi.IProgramaticCalloutProvider; import org.adempiere.ad.dao.cache.IModelCacheService; import org.adempiere.ad.modelvalidator.AbstractModuleInterceptor; import org.adempiere.ad.modelvalidator.IModelValidationEngine; import org.adempiere.util.jmx.JMXRegistry; import org.adempiere.util.jmx.JMXRegistry.OnJMXAlreadyExistsPolicy; +import org.compiere.Adempiere; +import org.compiere.Adempiere.RunMode; import org.compiere.model.I_AD_Client; import org.compiere.model.I_S_Resource; import org.compiere.model.I_S_ResourceType; import org.compiere.util.Env; +import org.compiere.util.Ini; +import org.eevolution.event.MaterialDocumentListener; import org.eevolution.mrp.jmx.JMXMRPStatus; +import de.metas.material.event.MaterialEventService; + /** * Libero Validator * * @author Victor Perez - * @author Trifon Trifonov
  • [ 2270421 ] Can not complete Shipment (Customer)
  • + * @author Trifon Trifonov + *
  • [ 2270421 ] Can not complete Shipment (Customer)
  • * @author Teo Sarca, www.arhipac.ro */ public final class LiberoValidator extends AbstractModuleInterceptor @@ -84,9 +90,9 @@ protected void registerInterceptors(final IModelValidationEngine engine, final I // Register MRP model validators // NOTE: keep this as the last model validators to register // NOTE2: from task 09944 we decided to register the MRP main interceptor from AD_ModelValidator, to be able to disable it. - //engine.addModelValidator(org.eevolution.model.validator.MRPInterceptor.instance, client); + // engine.addModelValidator(org.eevolution.model.validator.MRPInterceptor.instance, client); } - + @Override protected void registerCallouts(IProgramaticCalloutProvider calloutsRegistry) { @@ -114,4 +120,28 @@ public void onUserLogin(final int AD_Org_ID, final int AD_Role_ID, final int AD_ { Env.setContext(Env.getCtx(), CTX_IsLiberoEnabled, true); } + + @Override + protected void onAfterInit() + { + if(Adempiere.isUnitTestMode()) + { + // for the time being, this stuff does not belong with unit tests! + // feel free to revise + return; + } + + // add ourselves to the eventbus so that we can fire events on PP_Order docActions + final MaterialEventService materialEventService = Adempiere.getBean(MaterialEventService.class); + materialEventService.subscribeToEventBus(); + + if (Ini.getRunMode() != RunMode.BACKEND) + { + return; // event based material planning can only run in the backend as of now + } + + // register ourselves as listeners so we can respond to requests from the disposition framework + final MaterialDocumentListener materialDocumentListener = Adempiere.getBean(MaterialDocumentListener.class); + materialEventService.registerListener(materialDocumentListener); + } } // LiberoValidator diff --git a/de.metas.adempiere.libero.libero/src/main/java/org/eevolution/model/validator/PP_Order.java b/de.metas.adempiere.libero.libero/src/main/java/org/eevolution/model/validator/PP_Order.java index 42b5f0016b2..1eef4e87521 100644 --- a/de.metas.adempiere.libero.libero/src/main/java/org/eevolution/model/validator/PP_Order.java +++ b/de.metas.adempiere.libero.libero/src/main/java/org/eevolution/model/validator/PP_Order.java @@ -24,7 +24,6 @@ import java.math.BigDecimal; import java.sql.Timestamp; -import java.time.Instant; import java.util.List; import org.adempiere.ad.callout.spi.IProgramaticCalloutProvider; @@ -38,6 +37,7 @@ import org.adempiere.model.InterfaceWrapperHelper; import org.adempiere.util.Services; import org.adempiere.warehouse.api.IWarehouseBL; +import org.compiere.Adempiere; import org.compiere.model.I_C_DocType; import org.compiere.model.I_C_UOM; import org.compiere.model.I_M_AttributeSetInstance; @@ -54,12 +54,13 @@ import org.eevolution.api.IPPOrderWorkflowDAO; import org.eevolution.exceptions.LiberoException; import org.eevolution.model.I_DD_Order; -import org.eevolution.model.I_DD_OrderLine; import org.eevolution.model.I_PP_Order; import org.eevolution.model.I_PP_Order_BOM; import org.eevolution.model.I_PP_Order_BOMLine; import org.eevolution.model.X_PP_Order; +import de.metas.material.event.EventDescr; +import de.metas.material.event.MaterialEventService; import de.metas.material.event.ProductionPlanEvent; import de.metas.material.event.pporder.PPOrder; import de.metas.material.event.pporder.PPOrder.PPOrderBuilder; @@ -75,7 +76,7 @@ public class PP_Order public void registerCallouts() { Services.get(IProgramaticCalloutProvider.class).registerAnnotatedCallout(new org.eevolution.callout.PP_Order()); - + Services.get(ITabCalloutFactory.class).registerTabCalloutForTable(I_PP_Order.Table_Name, org.eevolution.callout.PP_Order_TabCallout.class); } @@ -262,26 +263,31 @@ private void createWorkflowAndBOM(final I_PP_Order ppOrder) Services.get(IPPOrderBOMBL.class).createOrderBOMAndLines(ppOrder); } - @DocValidate(timings = ModelValidator.TIMING_AFTER_COMPLETE) - public void preventForwardDDOrderToBeCleanedUp(final I_PP_Order ppOrder) - { - final IDDOrderDAO ddOrderDAO = Services.get(IDDOrderDAO.class); - - final List forwardDDOrdersToDisallowCleanup = ddOrderDAO.retrieveForwardDDOrderLinesQuery(ppOrder) - .andCollect(I_DD_OrderLine.COLUMN_DD_Order_ID) - .addEqualsFilter(I_DD_Order.COLUMNNAME_MRP_AllowCleanup, true) - .create() - .list(); - - for (final I_DD_Order ddOrder : forwardDDOrdersToDisallowCleanup) - { - if (ddOrder.isMRP_AllowCleanup()) - { - ddOrder.setMRP_AllowCleanup(false); - InterfaceWrapperHelper.save(ddOrder); - } - } - } + // commenting this out, to prevent + // org.eevolution.exceptions.LiberoException: No MRP supply record found for MPPOrder[ID=1047383-DocumentNo=1045999,IsSOTrx=false,C_DocType_ID=1000037] + // at org.eevolution.api.impl.DDOrderDAO.retrieveForwardDDOrderLinesQuery(DDOrderDAO.java:232) + // at org.eevolution.model.validator.PP_Order.preventForwardDDOrderToBeCleanedUp(PP_Order.java:272) + // + // @DocValidate(timings = ModelValidator.TIMING_AFTER_COMPLETE) + // public void preventForwardDDOrderToBeCleanedUp(final I_PP_Order ppOrder) + // { + // final IDDOrderDAO ddOrderDAO = Services.get(IDDOrderDAO.class); + // + // final List forwardDDOrdersToDisallowCleanup = ddOrderDAO.retrieveForwardDDOrderLinesQuery(ppOrder) + // .andCollect(I_DD_OrderLine.COLUMN_DD_Order_ID) + // .addEqualsFilter(I_DD_Order.COLUMNNAME_MRP_AllowCleanup, true) + // .create() + // .list(); + // + // for (final I_DD_Order ddOrder : forwardDDOrdersToDisallowCleanup) + // { + // if (ddOrder.isMRP_AllowCleanup()) + // { + // ddOrder.setMRP_AllowCleanup(false); + // InterfaceWrapperHelper.save(ddOrder); + // } + // } + // } /** * When manufacturing order is completed by the user, complete supply DD Orders. @@ -306,13 +312,14 @@ public void completeBackwardDDOrders_IfUserCompleted(final I_PP_Order ppOrder) ddOrderBL.completeDDOrdersIfNeeded(ddOrders); } - @DocValidate(timings = { ModelValidator.TIMING_AFTER_COMPLETE, - ModelValidator.TIMING_AFTER_REACTIVATE, - ModelValidator.TIMING_AFTER_CLOSE, - ModelValidator.TIMING_AFTER_UNCLOSE }) - public void fireMaterialEvent(final I_PP_Order ppOrder) + @ModelChange(timings = { + ModelValidator.TYPE_AFTER_NEW, ModelValidator.TYPE_AFTER_CHANGE + }, ifColumnsChanged = I_PP_Order.COLUMNNAME_DocStatus) + public void fireMaterialEvent(final I_PP_Order ppOrder, final int timing) { - + // when going with @DocAction, here the ppOrder's docStatus would still be "IP" even if we are invoked on afterComplete.. + // also, it might still be rolled back + // those aren't show-stoppers, but we therefore rather work with @ModelChange final PPOrderBuilder ppOrderPojoBuilder = PPOrder.builder() .datePromised(ppOrder.getDatePromised()) .dateStartSchedule(ppOrder.getDateStartSchedule()) @@ -325,10 +332,11 @@ public void fireMaterialEvent(final I_PP_Order ppOrder) .productPlanningId(ppOrder.getPP_Product_Planning_ID()) .quantity(ppOrder.getQtyOrdered()) .uomId(ppOrder.getC_UOM_ID()) - .warehouseId(ppOrder.getM_Warehouse_ID()); + .warehouseId(ppOrder.getM_Warehouse_ID()) + .orderLineId(ppOrder.getC_OrderLine_ID()); final List orderBOMLines = Services.get(IPPOrderBOMDAO.class).retrieveOrderBOMLines(ppOrder); - for (I_PP_Order_BOMLine line : orderBOMLines) + for (final I_PP_Order_BOMLine line : orderBOMLines) { ppOrderPojoBuilder.line(PPOrderLine.builder() .attributeSetInstanceId(line.getM_AttributeSetInstance_ID()) @@ -342,13 +350,13 @@ public void fireMaterialEvent(final I_PP_Order ppOrder) } final ProductionPlanEvent event = ProductionPlanEvent.builder() - .when(Instant.now()) + .eventDescr(new EventDescr()) .ppOrder(ppOrderPojoBuilder.build()) - // .reference(reference) + // .reference(reference) // we don't know the reference here, but we expect that the event-receiver (i.e. material-dispo) will be able to sort out which record(s) to update via date, orderLineId etc .build(); - - ; + final MaterialEventService materialEventService = Adempiere.getBean(MaterialEventService.class); + materialEventService.fireEventAfterCommit(event, InterfaceWrapperHelper.getTrxName(ppOrder)); } } diff --git a/de.metas.adempiere.libero.libero/src/test/java/de/metas/material/planning/pporder/impl/PPOrderBOMBLTest.java b/de.metas.adempiere.libero.libero/src/test/java/de/metas/material/planning/pporder/impl/PPOrderBOMBLTest.java index 7d631cefc35..f7daa091baf 100644 --- a/de.metas.adempiere.libero.libero/src/test/java/de/metas/material/planning/pporder/impl/PPOrderBOMBLTest.java +++ b/de.metas.adempiere.libero.libero/src/test/java/de/metas/material/planning/pporder/impl/PPOrderBOMBLTest.java @@ -10,12 +10,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -54,11 +54,10 @@ import de.metas.material.planning.MaterialPlanningConfiguration; import de.metas.material.planning.pporder.IPPOrderBOMBL; -import de.metas.material.planning.pporder.impl.PPOrderBOMBL; /** * This class tests {@link IPPOrderBOMBL} in convert with {@link IPPOrderBOMDAO}. - * + * * @author metas-dev * */ @@ -74,7 +73,7 @@ public class PPOrderBOMBLTest @Autowired private PPOrderBOMBL ppOrderBOMBL; // Other services - + private IPPOrderBOMDAO ppOrderBOMDAO; @Before @@ -181,7 +180,7 @@ public void qualityMultiplierTest() final I_PP_Order_BOMLine ppOrderBOMLine_Carrot = ppOrderBOMDAO.retrieveOrderBOMLine(ppOrder, pCarrot); assertUOM(expectedUOM, ppOrderBOMLine_Carrot); - BigDecimal multipliedQty = ppOrderBOMBL.getQtyMultiplier(ppOrderBOMLine_Carrot); // lineCarrot + BigDecimal multipliedQty = ppOrderBOMBL.getQtyMultiplier(ppOrderBOMBL.fromRecord(ppOrderBOMLine_Carrot)); // lineCarrot Assert.assertTrue("Should be" + expectedQty + "but it is " + multipliedQty, expectedQty.compareTo(multipliedQty) == 0); } @@ -194,7 +193,7 @@ public void qualityMultiplierTest() final I_PP_Order_BOMLine ppOrderBOMLine_Frisee = ppOrderBOMDAO.retrieveOrderBOMLine(ppOrder, pFrisee); assertUOM(expectedUOM, ppOrderBOMLine_Frisee); - final BigDecimal multipliedQty = ppOrderBOMBL.getQtyMultiplier(ppOrderBOMLine_Frisee); // lineFrisee + final BigDecimal multipliedQty = ppOrderBOMBL.getQtyMultiplier(ppOrderBOMBL.fromRecord(ppOrderBOMLine_Frisee)); // lineFrisee Assert.assertTrue("Should be" + expectedQty + "but it is " + multipliedQty, expectedQty.compareTo(multipliedQty) == 0); } @@ -207,7 +206,7 @@ public void qualityMultiplierTest() final I_PP_Order_BOMLine ppOrderBOMLine_Radiesli = ppOrderBOMDAO.retrieveOrderBOMLine(ppOrder, pRadiesli); assertUOM(expectedUOM, ppOrderBOMLine_Radiesli); - final BigDecimal multipliedQty = ppOrderBOMBL.getQtyMultiplier(ppOrderBOMLine_Radiesli); // lineRadisli + final BigDecimal multipliedQty = ppOrderBOMBL.getQtyMultiplier(ppOrderBOMBL.fromRecord(ppOrderBOMLine_Radiesli)); // lineRadisli Assert.assertTrue("Should be" + expectedQty + "but it is " + multipliedQty, expectedQty.compareTo(multipliedQty) == 0); } @@ -220,7 +219,7 @@ public void qualityMultiplierTest() final I_PP_Order_BOMLine ppOrderBOMLine_Folie = ppOrderBOMDAO.retrieveOrderBOMLine(ppOrder, pFolie); assertUOM(expectedUOM, ppOrderBOMLine_Folie); - final BigDecimal multipliedQty = ppOrderBOMBL.getQtyMultiplier(ppOrderBOMLine_Folie); // lineFolie + final BigDecimal multipliedQty = ppOrderBOMBL.getQtyMultiplier(ppOrderBOMBL.fromRecord(ppOrderBOMLine_Folie)); // lineFolie Assert.assertTrue("Should be" + expectedQty + "but it is " + multipliedQty, expectedQty.compareTo(multipliedQty) == 0); } } @@ -233,7 +232,7 @@ private I_PP_Order createPP_Order(final I_PP_Product_BOM productBOM, final Strin ppOrder.setAD_Org(masterData.adOrg01); setCommonProperties(ppOrder); - + ppOrder.setM_Product(product); ppOrder.setPP_Product_BOM(productBOM); ppOrder.setAD_Workflow(masterData.workflow_Standard); @@ -251,13 +250,13 @@ private I_PP_Order createPP_Order(final I_PP_Product_BOM productBOM, final Strin private void setCommonProperties(final I_PP_Order ppOrder) { Services.get(IPPOrderBL.class).setDocType(ppOrder, X_C_DocType.DOCBASETYPE_ManufacturingOrder, null); - + // required to avoid an NPE when building the lightweight PPOrder pojo final Timestamp t1 = SystemTime.asTimestamp(); ppOrder.setDateOrdered(t1); ppOrder.setDateStartSchedule(t1); } - + private I_C_UOM createUOM(final String name, final int stdPrecision, final int costingPrecission) { final I_C_UOM uom = helper.createUOM(name); diff --git a/de.metas.material/dispo/manufacturing-dispo_GenerateModels.launch b/de.metas.material/dispo/material-dispo_GenerateModels.launch similarity index 91% rename from de.metas.material/dispo/manufacturing-dispo_GenerateModels.launch rename to de.metas.material/dispo/material-dispo_GenerateModels.launch index 350d111ccc6..da63133b225 100644 --- a/de.metas.material/dispo/manufacturing-dispo_GenerateModels.launch +++ b/de.metas.material/dispo/material-dispo_GenerateModels.launch @@ -2,10 +2,10 @@ - + - + diff --git a/de.metas.material/dispo/src/main/java-gen/de/metas/material/dispo/model/I_MD_Candidate_Demand_Detail.java b/de.metas.material/dispo/src/main/java-gen/de/metas/material/dispo/model/I_MD_Candidate_Demand_Detail.java new file mode 100644 index 00000000000..3d3831b9c3e --- /dev/null +++ b/de.metas.material/dispo/src/main/java-gen/de/metas/material/dispo/model/I_MD_Candidate_Demand_Detail.java @@ -0,0 +1,234 @@ +package de.metas.material.dispo.model; + + +/** Generated Interface for MD_Candidate_Demand_Detail + * @author Adempiere (generated) + */ +@SuppressWarnings("javadoc") +public interface I_MD_Candidate_Demand_Detail +{ + + /** TableName=MD_Candidate_Demand_Detail */ + public static final String Table_Name = "MD_Candidate_Demand_Detail"; + + /** AD_Table_ID=540815 */ +// public static final int Table_ID = org.compiere.model.MTable.getTable_ID(Table_Name); + +// org.compiere.util.KeyNamePair Model = new org.compiere.util.KeyNamePair(Table_ID, Table_Name); + + /** AccessLevel = 1 - Org + */ +// java.math.BigDecimal accessLevel = java.math.BigDecimal.valueOf(1); + + /** Load Meta Data */ + + /** + * Get Mandant. + * Mandant für diese Installation. + * + *
    Type: TableDir + *
    Mandatory: true + *
    Virtual Column: false + */ + public int getAD_Client_ID(); + + public org.compiere.model.I_AD_Client getAD_Client(); + + /** Column definition for AD_Client_ID */ + public static final org.adempiere.model.ModelColumn COLUMN_AD_Client_ID = new org.adempiere.model.ModelColumn(I_MD_Candidate_Demand_Detail.class, "AD_Client_ID", org.compiere.model.I_AD_Client.class); + /** Column name AD_Client_ID */ + public static final String COLUMNNAME_AD_Client_ID = "AD_Client_ID"; + + /** + * Set Sektion. + * Organisatorische Einheit des Mandanten + * + *
    Type: TableDir + *
    Mandatory: true + *
    Virtual Column: false + */ + public void setAD_Org_ID (int AD_Org_ID); + + /** + * Get Sektion. + * Organisatorische Einheit des Mandanten + * + *
    Type: TableDir + *
    Mandatory: true + *
    Virtual Column: false + */ + public int getAD_Org_ID(); + + public org.compiere.model.I_AD_Org getAD_Org(); + + public void setAD_Org(org.compiere.model.I_AD_Org AD_Org); + + /** Column definition for AD_Org_ID */ + public static final org.adempiere.model.ModelColumn COLUMN_AD_Org_ID = new org.adempiere.model.ModelColumn(I_MD_Candidate_Demand_Detail.class, "AD_Org_ID", org.compiere.model.I_AD_Org.class); + /** Column name AD_Org_ID */ + public static final String COLUMNNAME_AD_Org_ID = "AD_Org_ID"; + + /** + * Set Auftragsposition. + * Auftragsposition + * + *
    Type: Search + *
    Mandatory: false + *
    Virtual Column: false + */ + public void setC_OrderLine_ID (int C_OrderLine_ID); + + /** + * Get Auftragsposition. + * Auftragsposition + * + *
    Type: Search + *
    Mandatory: false + *
    Virtual Column: false + */ + public int getC_OrderLine_ID(); + + public org.compiere.model.I_C_OrderLine getC_OrderLine(); + + public void setC_OrderLine(org.compiere.model.I_C_OrderLine C_OrderLine); + + /** Column definition for C_OrderLine_ID */ + public static final org.adempiere.model.ModelColumn COLUMN_C_OrderLine_ID = new org.adempiere.model.ModelColumn(I_MD_Candidate_Demand_Detail.class, "C_OrderLine_ID", org.compiere.model.I_C_OrderLine.class); + /** Column name C_OrderLine_ID */ + public static final String COLUMNNAME_C_OrderLine_ID = "C_OrderLine_ID"; + + /** + * Get Erstellt. + * Datum, an dem dieser Eintrag erstellt wurde + * + *
    Type: DateTime + *
    Mandatory: true + *
    Virtual Column: false + */ + public java.sql.Timestamp getCreated(); + + /** Column definition for Created */ + public static final org.adempiere.model.ModelColumn COLUMN_Created = new org.adempiere.model.ModelColumn(I_MD_Candidate_Demand_Detail.class, "Created", null); + /** Column name Created */ + public static final String COLUMNNAME_Created = "Created"; + + /** + * Get Erstellt durch. + * Nutzer, der diesen Eintrag erstellt hat + * + *
    Type: Table + *
    Mandatory: true + *
    Virtual Column: false + */ + public int getCreatedBy(); + + /** Column definition for CreatedBy */ + public static final org.adempiere.model.ModelColumn COLUMN_CreatedBy = new org.adempiere.model.ModelColumn(I_MD_Candidate_Demand_Detail.class, "CreatedBy", org.compiere.model.I_AD_User.class); + /** Column name CreatedBy */ + public static final String COLUMNNAME_CreatedBy = "CreatedBy"; + + /** + * Set Aktiv. + * Der Eintrag ist im System aktiv + * + *
    Type: YesNo + *
    Mandatory: true + *
    Virtual Column: false + */ + public void setIsActive (boolean IsActive); + + /** + * Get Aktiv. + * Der Eintrag ist im System aktiv + * + *
    Type: YesNo + *
    Mandatory: true + *
    Virtual Column: false + */ + public boolean isActive(); + + /** Column definition for IsActive */ + public static final org.adempiere.model.ModelColumn COLUMN_IsActive = new org.adempiere.model.ModelColumn(I_MD_Candidate_Demand_Detail.class, "IsActive", null); + /** Column name IsActive */ + public static final String COLUMNNAME_IsActive = "IsActive"; + + /** + * Set Dispo-Bedarfsdetail. + * + *
    Type: ID + *
    Mandatory: true + *
    Virtual Column: false + */ + public void setMD_Candidate_Demand_Detail_ID (int MD_Candidate_Demand_Detail_ID); + + /** + * Get Dispo-Bedarfsdetail. + * + *
    Type: ID + *
    Mandatory: true + *
    Virtual Column: false + */ + public int getMD_Candidate_Demand_Detail_ID(); + + /** Column definition for MD_Candidate_Demand_Detail_ID */ + public static final org.adempiere.model.ModelColumn COLUMN_MD_Candidate_Demand_Detail_ID = new org.adempiere.model.ModelColumn(I_MD_Candidate_Demand_Detail.class, "MD_Candidate_Demand_Detail_ID", null); + /** Column name MD_Candidate_Demand_Detail_ID */ + public static final String COLUMNNAME_MD_Candidate_Demand_Detail_ID = "MD_Candidate_Demand_Detail_ID"; + + /** + * Set Dispositionskandidat. + * + *
    Type: Search + *
    Mandatory: true + *
    Virtual Column: false + */ + public void setMD_Candidate_ID (int MD_Candidate_ID); + + /** + * Get Dispositionskandidat. + * + *
    Type: Search + *
    Mandatory: true + *
    Virtual Column: false + */ + public int getMD_Candidate_ID(); + + public de.metas.material.dispo.model.I_MD_Candidate getMD_Candidate(); + + public void setMD_Candidate(de.metas.material.dispo.model.I_MD_Candidate MD_Candidate); + + /** Column definition for MD_Candidate_ID */ + public static final org.adempiere.model.ModelColumn COLUMN_MD_Candidate_ID = new org.adempiere.model.ModelColumn(I_MD_Candidate_Demand_Detail.class, "MD_Candidate_ID", de.metas.material.dispo.model.I_MD_Candidate.class); + /** Column name MD_Candidate_ID */ + public static final String COLUMNNAME_MD_Candidate_ID = "MD_Candidate_ID"; + + /** + * Get Aktualisiert. + * Datum, an dem dieser Eintrag aktualisiert wurde + * + *
    Type: DateTime + *
    Mandatory: true + *
    Virtual Column: false + */ + public java.sql.Timestamp getUpdated(); + + /** Column definition for Updated */ + public static final org.adempiere.model.ModelColumn COLUMN_Updated = new org.adempiere.model.ModelColumn(I_MD_Candidate_Demand_Detail.class, "Updated", null); + /** Column name Updated */ + public static final String COLUMNNAME_Updated = "Updated"; + + /** + * Get Aktualisiert durch. + * Nutzer, der diesen Eintrag aktualisiert hat + * + *
    Type: Table + *
    Mandatory: true + *
    Virtual Column: false + */ + public int getUpdatedBy(); + + /** Column definition for UpdatedBy */ + public static final org.adempiere.model.ModelColumn COLUMN_UpdatedBy = new org.adempiere.model.ModelColumn(I_MD_Candidate_Demand_Detail.class, "UpdatedBy", org.compiere.model.I_AD_User.class); + /** Column name UpdatedBy */ + public static final String COLUMNNAME_UpdatedBy = "UpdatedBy"; +} diff --git a/de.metas.material/dispo/src/main/java-gen/de/metas/material/dispo/model/I_MD_EventStore.java b/de.metas.material/dispo/src/main/java-gen/de/metas/material/dispo/model/I_MD_EventStore.java new file mode 100644 index 00000000000..00d4ec349a8 --- /dev/null +++ b/de.metas.material/dispo/src/main/java-gen/de/metas/material/dispo/model/I_MD_EventStore.java @@ -0,0 +1,328 @@ +package de.metas.material.dispo.model; + + +/** Generated Interface for MD_EventStore + * @author Adempiere (generated) + */ +@SuppressWarnings("javadoc") +public interface I_MD_EventStore +{ + + /** TableName=MD_EventStore */ + public static final String Table_Name = "MD_EventStore"; + + /** AD_Table_ID=540814 */ +// public static final int Table_ID = org.compiere.model.MTable.getTable_ID(Table_Name); + +// org.compiere.util.KeyNamePair Model = new org.compiere.util.KeyNamePair(Table_ID, Table_Name); + + /** AccessLevel = 4 - System + */ +// java.math.BigDecimal accessLevel = java.math.BigDecimal.valueOf(4); + + /** Load Meta Data */ + + /** + * Get Mandant. + * Mandant für diese Installation. + * + *
    Type: TableDir + *
    Mandatory: true + *
    Virtual Column: false + */ + public int getAD_Client_ID(); + + public org.compiere.model.I_AD_Client getAD_Client(); + + /** Column definition for AD_Client_ID */ + public static final org.adempiere.model.ModelColumn COLUMN_AD_Client_ID = new org.adempiere.model.ModelColumn(I_MD_EventStore.class, "AD_Client_ID", org.compiere.model.I_AD_Client.class); + /** Column name AD_Client_ID */ + public static final String COLUMNNAME_AD_Client_ID = "AD_Client_ID"; + + /** + * Set System-Problem. + * Automatically created or manually entered System Issue + * + *
    Type: Search + *
    Mandatory: false + *
    Virtual Column: false + */ + public void setAD_Issue_ID (int AD_Issue_ID); + + /** + * Get System-Problem. + * Automatically created or manually entered System Issue + * + *
    Type: Search + *
    Mandatory: false + *
    Virtual Column: false + */ + public int getAD_Issue_ID(); + + public org.compiere.model.I_AD_Issue getAD_Issue(); + + public void setAD_Issue(org.compiere.model.I_AD_Issue AD_Issue); + + /** Column definition for AD_Issue_ID */ + public static final org.adempiere.model.ModelColumn COLUMN_AD_Issue_ID = new org.adempiere.model.ModelColumn(I_MD_EventStore.class, "AD_Issue_ID", org.compiere.model.I_AD_Issue.class); + /** Column name AD_Issue_ID */ + public static final String COLUMNNAME_AD_Issue_ID = "AD_Issue_ID"; + + /** + * Set Sektion. + * Organisatorische Einheit des Mandanten + * + *
    Type: TableDir + *
    Mandatory: true + *
    Virtual Column: false + */ + public void setAD_Org_ID (int AD_Org_ID); + + /** + * Get Sektion. + * Organisatorische Einheit des Mandanten + * + *
    Type: TableDir + *
    Mandatory: true + *
    Virtual Column: false + */ + public int getAD_Org_ID(); + + public org.compiere.model.I_AD_Org getAD_Org(); + + public void setAD_Org(org.compiere.model.I_AD_Org AD_Org); + + /** Column definition for AD_Org_ID */ + public static final org.adempiere.model.ModelColumn COLUMN_AD_Org_ID = new org.adempiere.model.ModelColumn(I_MD_EventStore.class, "AD_Org_ID", org.compiere.model.I_AD_Org.class); + /** Column name AD_Org_ID */ + public static final String COLUMNNAME_AD_Org_ID = "AD_Org_ID"; + + /** + * Get Erstellt. + * Datum, an dem dieser Eintrag erstellt wurde + * + *
    Type: DateTime + *
    Mandatory: true + *
    Virtual Column: false + */ + public java.sql.Timestamp getCreated(); + + /** Column definition for Created */ + public static final org.adempiere.model.ModelColumn COLUMN_Created = new org.adempiere.model.ModelColumn(I_MD_EventStore.class, "Created", null); + /** Column name Created */ + public static final String COLUMNNAME_Created = "Created"; + + /** + * Get Erstellt durch. + * Nutzer, der diesen Eintrag erstellt hat + * + *
    Type: Table + *
    Mandatory: true + *
    Virtual Column: false + */ + public int getCreatedBy(); + + /** Column definition for CreatedBy */ + public static final org.adempiere.model.ModelColumn COLUMN_CreatedBy = new org.adempiere.model.ModelColumn(I_MD_EventStore.class, "CreatedBy", org.compiere.model.I_AD_User.class); + /** Column name CreatedBy */ + public static final String COLUMNNAME_CreatedBy = "CreatedBy"; + + /** + * Set Event UUID. + * + *
    Type: String + *
    Mandatory: true + *
    Virtual Column: false + */ + public void setEvent_UUID (java.lang.String Event_UUID); + + /** + * Get Event UUID. + * + *
    Type: String + *
    Mandatory: true + *
    Virtual Column: false + */ + public java.lang.String getEvent_UUID(); + + /** Column definition for Event_UUID */ + public static final org.adempiere.model.ModelColumn COLUMN_Event_UUID = new org.adempiere.model.ModelColumn(I_MD_EventStore.class, "Event_UUID", null); + /** Column name Event_UUID */ + public static final String COLUMNNAME_Event_UUID = "Event_UUID"; + + /** + * Set Daten. + * + *
    Type: TextLong + *
    Mandatory: true + *
    Virtual Column: false + */ + public void setEventData (java.lang.String EventData); + + /** + * Get Daten. + * + *
    Type: TextLong + *
    Mandatory: true + *
    Virtual Column: false + */ + public java.lang.String getEventData(); + + /** Column definition for EventData */ + public static final org.adempiere.model.ModelColumn COLUMN_EventData = new org.adempiere.model.ModelColumn(I_MD_EventStore.class, "EventData", null); + /** Column name EventData */ + public static final String COLUMNNAME_EventData = "EventData"; + + /** + * Set Zeitpunkt. + * + *
    Type: DateTime + *
    Mandatory: true + *
    Virtual Column: false + */ + public void setEventTime (java.sql.Timestamp EventTime); + + /** + * Get Zeitpunkt. + * + *
    Type: DateTime + *
    Mandatory: true + *
    Virtual Column: false + */ + public java.sql.Timestamp getEventTime(); + + /** Column definition for EventTime */ + public static final org.adempiere.model.ModelColumn COLUMN_EventTime = new org.adempiere.model.ModelColumn(I_MD_EventStore.class, "EventTime", null); + /** Column name EventTime */ + public static final String COLUMNNAME_EventTime = "EventTime"; + + /** + * Set Aktiv. + * Der Eintrag ist im System aktiv + * + *
    Type: YesNo + *
    Mandatory: true + *
    Virtual Column: false + */ + public void setIsActive (boolean IsActive); + + /** + * Get Aktiv. + * Der Eintrag ist im System aktiv + * + *
    Type: YesNo + *
    Mandatory: true + *
    Virtual Column: false + */ + public boolean isActive(); + + /** Column definition for IsActive */ + public static final org.adempiere.model.ModelColumn COLUMN_IsActive = new org.adempiere.model.ModelColumn(I_MD_EventStore.class, "IsActive", null); + /** Column name IsActive */ + public static final String COLUMNNAME_IsActive = "IsActive"; + + /** + * Set Dispositionskandidat. + * + *
    Type: Search + *
    Mandatory: false + *
    Virtual Column: false + */ + public void setMD_Candidate_ID (int MD_Candidate_ID); + + /** + * Get Dispositionskandidat. + * + *
    Type: Search + *
    Mandatory: false + *
    Virtual Column: false + */ + public int getMD_Candidate_ID(); + + public de.metas.material.dispo.model.I_MD_Candidate getMD_Candidate(); + + public void setMD_Candidate(de.metas.material.dispo.model.I_MD_Candidate MD_Candidate); + + /** Column definition for MD_Candidate_ID */ + public static final org.adempiere.model.ModelColumn COLUMN_MD_Candidate_ID = new org.adempiere.model.ModelColumn(I_MD_EventStore.class, "MD_Candidate_ID", de.metas.material.dispo.model.I_MD_Candidate.class); + /** Column name MD_Candidate_ID */ + public static final String COLUMNNAME_MD_Candidate_ID = "MD_Candidate_ID"; + + /** + * Set Material-Dispo-Eventstore. + * + *
    Type: ID + *
    Mandatory: true + *
    Virtual Column: false + */ + public void setMD_EventStore_ID (int MD_EventStore_ID); + + /** + * Get Material-Dispo-Eventstore. + * + *
    Type: ID + *
    Mandatory: true + *
    Virtual Column: false + */ + public int getMD_EventStore_ID(); + + /** Column definition for MD_EventStore_ID */ + public static final org.adempiere.model.ModelColumn COLUMN_MD_EventStore_ID = new org.adempiere.model.ModelColumn(I_MD_EventStore.class, "MD_EventStore_ID", null); + /** Column name MD_EventStore_ID */ + public static final String COLUMNNAME_MD_EventStore_ID = "MD_EventStore_ID"; + + /** + * Set Verarbeitet. + * Checkbox sagt aus, ob der Beleg verarbeitet wurde. + * + *
    Type: YesNo + *
    Mandatory: true + *
    Virtual Column: false + */ + public void setProcessed (boolean Processed); + + /** + * Get Verarbeitet. + * Checkbox sagt aus, ob der Beleg verarbeitet wurde. + * + *
    Type: YesNo + *
    Mandatory: true + *
    Virtual Column: false + */ + public boolean isProcessed(); + + /** Column definition for Processed */ + public static final org.adempiere.model.ModelColumn COLUMN_Processed = new org.adempiere.model.ModelColumn(I_MD_EventStore.class, "Processed", null); + /** Column name Processed */ + public static final String COLUMNNAME_Processed = "Processed"; + + /** + * Get Aktualisiert. + * Datum, an dem dieser Eintrag aktualisiert wurde + * + *
    Type: DateTime + *
    Mandatory: true + *
    Virtual Column: false + */ + public java.sql.Timestamp getUpdated(); + + /** Column definition for Updated */ + public static final org.adempiere.model.ModelColumn COLUMN_Updated = new org.adempiere.model.ModelColumn(I_MD_EventStore.class, "Updated", null); + /** Column name Updated */ + public static final String COLUMNNAME_Updated = "Updated"; + + /** + * Get Aktualisiert durch. + * Nutzer, der diesen Eintrag aktualisiert hat + * + *
    Type: Table + *
    Mandatory: true + *
    Virtual Column: false + */ + public int getUpdatedBy(); + + /** Column definition for UpdatedBy */ + public static final org.adempiere.model.ModelColumn COLUMN_UpdatedBy = new org.adempiere.model.ModelColumn(I_MD_EventStore.class, "UpdatedBy", org.compiere.model.I_AD_User.class); + /** Column name UpdatedBy */ + public static final String COLUMNNAME_UpdatedBy = "UpdatedBy"; +} diff --git a/de.metas.material/dispo/src/main/java-gen/de/metas/material/dispo/model/X_MD_Candidate.java b/de.metas.material/dispo/src/main/java-gen/de/metas/material/dispo/model/X_MD_Candidate.java index d3e10b4f8ab..e84fcc3244b 100644 --- a/de.metas.material/dispo/src/main/java-gen/de/metas/material/dispo/model/X_MD_Candidate.java +++ b/de.metas.material/dispo/src/main/java-gen/de/metas/material/dispo/model/X_MD_Candidate.java @@ -16,7 +16,7 @@ public class X_MD_Candidate extends org.compiere.model.PO implements I_MD_Candid /** * */ - private static final long serialVersionUID = -1944893752L; + private static final long serialVersionUID = -1795260422L; /** Standard Constructor */ public X_MD_Candidate (Properties ctx, int MD_Candidate_ID, String trxName) @@ -294,10 +294,14 @@ public int getMD_Candidate_Parent_ID () * Reference name: MD_Candidate_Status */ public static final int MD_CANDIDATE_STATUS_AD_Reference_ID=540715; - /** fact = fact */ - public static final String MD_CANDIDATE_STATUS_Fact = "fact"; - /** planned = planned */ - public static final String MD_CANDIDATE_STATUS_Planned = "planned"; + /** doc_created = doc_created */ + public static final String MD_CANDIDATE_STATUS_Doc_created = "doc_created"; + /** doc_planned = doc_planned */ + public static final String MD_CANDIDATE_STATUS_Doc_planned = "doc_planned"; + /** doc_completed = doc_completed */ + public static final String MD_CANDIDATE_STATUS_Doc_completed = "doc_completed"; + /** doc_closed = doc_closed */ + public static final String MD_CANDIDATE_STATUS_Doc_closed = "doc_closed"; /** Set Status. @param MD_Candidate_Status Status */ @Override diff --git a/de.metas.material/dispo/src/main/java-gen/de/metas/material/dispo/model/X_MD_Candidate_Demand_Detail.java b/de.metas.material/dispo/src/main/java-gen/de/metas/material/dispo/model/X_MD_Candidate_Demand_Detail.java new file mode 100644 index 00000000000..8e391d435ec --- /dev/null +++ b/de.metas.material/dispo/src/main/java-gen/de/metas/material/dispo/model/X_MD_Candidate_Demand_Detail.java @@ -0,0 +1,137 @@ +/** Generated Model - DO NOT CHANGE */ +package de.metas.material.dispo.model; + +import java.sql.ResultSet; +import java.util.Properties; + +/** Generated Model for MD_Candidate_Demand_Detail + * @author Adempiere (generated) + */ +@SuppressWarnings("javadoc") +public class X_MD_Candidate_Demand_Detail extends org.compiere.model.PO implements I_MD_Candidate_Demand_Detail, org.compiere.model.I_Persistent +{ + + /** + * + */ + private static final long serialVersionUID = -2122643939L; + + /** Standard Constructor */ + public X_MD_Candidate_Demand_Detail (Properties ctx, int MD_Candidate_Demand_Detail_ID, String trxName) + { + super (ctx, MD_Candidate_Demand_Detail_ID, trxName); + /** if (MD_Candidate_Demand_Detail_ID == 0) + { + setMD_Candidate_Demand_Detail_ID (0); + setMD_Candidate_ID (0); + } */ + } + + /** Load Constructor */ + public X_MD_Candidate_Demand_Detail (Properties ctx, ResultSet rs, String trxName) + { + super (ctx, rs, trxName); + } + + + /** Load Meta Data */ + @Override + protected org.compiere.model.POInfo initPO (Properties ctx) + { + org.compiere.model.POInfo poi = org.compiere.model.POInfo.getPOInfo (ctx, Table_Name, get_TrxName()); + return poi; + } + + @Override + public org.compiere.model.I_C_OrderLine getC_OrderLine() throws RuntimeException + { + return get_ValueAsPO(COLUMNNAME_C_OrderLine_ID, org.compiere.model.I_C_OrderLine.class); + } + + @Override + public void setC_OrderLine(org.compiere.model.I_C_OrderLine C_OrderLine) + { + set_ValueFromPO(COLUMNNAME_C_OrderLine_ID, org.compiere.model.I_C_OrderLine.class, C_OrderLine); + } + + /** Set Auftragsposition. + @param C_OrderLine_ID + Auftragsposition + */ + @Override + public void setC_OrderLine_ID (int C_OrderLine_ID) + { + if (C_OrderLine_ID < 1) + set_Value (COLUMNNAME_C_OrderLine_ID, null); + else + set_Value (COLUMNNAME_C_OrderLine_ID, Integer.valueOf(C_OrderLine_ID)); + } + + /** Get Auftragsposition. + @return Auftragsposition + */ + @Override + public int getC_OrderLine_ID () + { + Integer ii = (Integer)get_Value(COLUMNNAME_C_OrderLine_ID); + if (ii == null) + return 0; + return ii.intValue(); + } + + /** Set Dispo-Bedarfsdetail. + @param MD_Candidate_Demand_Detail_ID Dispo-Bedarfsdetail */ + @Override + public void setMD_Candidate_Demand_Detail_ID (int MD_Candidate_Demand_Detail_ID) + { + if (MD_Candidate_Demand_Detail_ID < 1) + set_ValueNoCheck (COLUMNNAME_MD_Candidate_Demand_Detail_ID, null); + else + set_ValueNoCheck (COLUMNNAME_MD_Candidate_Demand_Detail_ID, Integer.valueOf(MD_Candidate_Demand_Detail_ID)); + } + + /** Get Dispo-Bedarfsdetail. + @return Dispo-Bedarfsdetail */ + @Override + public int getMD_Candidate_Demand_Detail_ID () + { + Integer ii = (Integer)get_Value(COLUMNNAME_MD_Candidate_Demand_Detail_ID); + if (ii == null) + return 0; + return ii.intValue(); + } + + @Override + public de.metas.material.dispo.model.I_MD_Candidate getMD_Candidate() throws RuntimeException + { + return get_ValueAsPO(COLUMNNAME_MD_Candidate_ID, de.metas.material.dispo.model.I_MD_Candidate.class); + } + + @Override + public void setMD_Candidate(de.metas.material.dispo.model.I_MD_Candidate MD_Candidate) + { + set_ValueFromPO(COLUMNNAME_MD_Candidate_ID, de.metas.material.dispo.model.I_MD_Candidate.class, MD_Candidate); + } + + /** Set Dispositionskandidat. + @param MD_Candidate_ID Dispositionskandidat */ + @Override + public void setMD_Candidate_ID (int MD_Candidate_ID) + { + if (MD_Candidate_ID < 1) + set_ValueNoCheck (COLUMNNAME_MD_Candidate_ID, null); + else + set_ValueNoCheck (COLUMNNAME_MD_Candidate_ID, Integer.valueOf(MD_Candidate_ID)); + } + + /** Get Dispositionskandidat. + @return Dispositionskandidat */ + @Override + public int getMD_Candidate_ID () + { + Integer ii = (Integer)get_Value(COLUMNNAME_MD_Candidate_ID); + if (ii == null) + return 0; + return ii.intValue(); + } +} \ No newline at end of file diff --git a/de.metas.material/dispo/src/main/java-gen/de/metas/material/dispo/model/X_MD_EventStore.java b/de.metas.material/dispo/src/main/java-gen/de/metas/material/dispo/model/X_MD_EventStore.java new file mode 100644 index 00000000000..2b2af15f5ad --- /dev/null +++ b/de.metas.material/dispo/src/main/java-gen/de/metas/material/dispo/model/X_MD_EventStore.java @@ -0,0 +1,215 @@ +/** Generated Model - DO NOT CHANGE */ +package de.metas.material.dispo.model; + +import java.sql.ResultSet; +import java.util.Properties; + +/** Generated Model for MD_EventStore + * @author Adempiere (generated) + */ +@SuppressWarnings("javadoc") +public class X_MD_EventStore extends org.compiere.model.PO implements I_MD_EventStore, org.compiere.model.I_Persistent +{ + + /** + * + */ + private static final long serialVersionUID = 2128673728L; + + /** Standard Constructor */ + public X_MD_EventStore (Properties ctx, int MD_EventStore_ID, String trxName) + { + super (ctx, MD_EventStore_ID, trxName); + /** if (MD_EventStore_ID == 0) + { + setEvent_UUID (null); + setEventData (null); + setEventTime (new Timestamp( System.currentTimeMillis() )); + setMD_EventStore_ID (0); + setProcessed (false); +// N + } */ + } + + /** Load Constructor */ + public X_MD_EventStore (Properties ctx, ResultSet rs, String trxName) + { + super (ctx, rs, trxName); + } + + + /** Load Meta Data */ + @Override + protected org.compiere.model.POInfo initPO (Properties ctx) + { + org.compiere.model.POInfo poi = org.compiere.model.POInfo.getPOInfo (ctx, Table_Name, get_TrxName()); + return poi; + } + + @Override + public org.compiere.model.I_AD_Issue getAD_Issue() throws RuntimeException + { + return get_ValueAsPO(COLUMNNAME_AD_Issue_ID, org.compiere.model.I_AD_Issue.class); + } + + @Override + public void setAD_Issue(org.compiere.model.I_AD_Issue AD_Issue) + { + set_ValueFromPO(COLUMNNAME_AD_Issue_ID, org.compiere.model.I_AD_Issue.class, AD_Issue); + } + + /** Set System-Problem. + @param AD_Issue_ID + Automatically created or manually entered System Issue + */ + @Override + public void setAD_Issue_ID (int AD_Issue_ID) + { + if (AD_Issue_ID < 1) + set_Value (COLUMNNAME_AD_Issue_ID, null); + else + set_Value (COLUMNNAME_AD_Issue_ID, Integer.valueOf(AD_Issue_ID)); + } + + /** Get System-Problem. + @return Automatically created or manually entered System Issue + */ + @Override + public int getAD_Issue_ID () + { + Integer ii = (Integer)get_Value(COLUMNNAME_AD_Issue_ID); + if (ii == null) + return 0; + return ii.intValue(); + } + + /** Set Event UUID. + @param Event_UUID Event UUID */ + @Override + public void setEvent_UUID (java.lang.String Event_UUID) + { + set_ValueNoCheck (COLUMNNAME_Event_UUID, Event_UUID); + } + + /** Get Event UUID. + @return Event UUID */ + @Override + public java.lang.String getEvent_UUID () + { + return (java.lang.String)get_Value(COLUMNNAME_Event_UUID); + } + + /** Set Daten. + @param EventData Daten */ + @Override + public void setEventData (java.lang.String EventData) + { + set_ValueNoCheck (COLUMNNAME_EventData, EventData); + } + + /** Get Daten. + @return Daten */ + @Override + public java.lang.String getEventData () + { + return (java.lang.String)get_Value(COLUMNNAME_EventData); + } + + /** Set Zeitpunkt. + @param EventTime Zeitpunkt */ + @Override + public void setEventTime (java.sql.Timestamp EventTime) + { + set_ValueNoCheck (COLUMNNAME_EventTime, EventTime); + } + + /** Get Zeitpunkt. + @return Zeitpunkt */ + @Override + public java.sql.Timestamp getEventTime () + { + return (java.sql.Timestamp)get_Value(COLUMNNAME_EventTime); + } + + @Override + public de.metas.material.dispo.model.I_MD_Candidate getMD_Candidate() throws RuntimeException + { + return get_ValueAsPO(COLUMNNAME_MD_Candidate_ID, de.metas.material.dispo.model.I_MD_Candidate.class); + } + + @Override + public void setMD_Candidate(de.metas.material.dispo.model.I_MD_Candidate MD_Candidate) + { + set_ValueFromPO(COLUMNNAME_MD_Candidate_ID, de.metas.material.dispo.model.I_MD_Candidate.class, MD_Candidate); + } + + /** Set Dispositionskandidat. + @param MD_Candidate_ID Dispositionskandidat */ + @Override + public void setMD_Candidate_ID (int MD_Candidate_ID) + { + if (MD_Candidate_ID < 1) + set_Value (COLUMNNAME_MD_Candidate_ID, null); + else + set_Value (COLUMNNAME_MD_Candidate_ID, Integer.valueOf(MD_Candidate_ID)); + } + + /** Get Dispositionskandidat. + @return Dispositionskandidat */ + @Override + public int getMD_Candidate_ID () + { + Integer ii = (Integer)get_Value(COLUMNNAME_MD_Candidate_ID); + if (ii == null) + return 0; + return ii.intValue(); + } + + /** Set Material-Dispo-Eventstore. + @param MD_EventStore_ID Material-Dispo-Eventstore */ + @Override + public void setMD_EventStore_ID (int MD_EventStore_ID) + { + if (MD_EventStore_ID < 1) + set_ValueNoCheck (COLUMNNAME_MD_EventStore_ID, null); + else + set_ValueNoCheck (COLUMNNAME_MD_EventStore_ID, Integer.valueOf(MD_EventStore_ID)); + } + + /** Get Material-Dispo-Eventstore. + @return Material-Dispo-Eventstore */ + @Override + public int getMD_EventStore_ID () + { + Integer ii = (Integer)get_Value(COLUMNNAME_MD_EventStore_ID); + if (ii == null) + return 0; + return ii.intValue(); + } + + /** Set Verarbeitet. + @param Processed + Checkbox sagt aus, ob der Beleg verarbeitet wurde. + */ + @Override + public void setProcessed (boolean Processed) + { + set_ValueNoCheck (COLUMNNAME_Processed, Boolean.valueOf(Processed)); + } + + /** Get Verarbeitet. + @return Checkbox sagt aus, ob der Beleg verarbeitet wurde. + */ + @Override + public boolean isProcessed () + { + Object oo = get_Value(COLUMNNAME_Processed); + if (oo != null) + { + if (oo instanceof Boolean) + return ((Boolean)oo).booleanValue(); + return "Y".equals(oo); + } + return false; + } +} \ No newline at end of file diff --git a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/Application.java b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/Application.java index cfaf11df6db..54555c4a709 100644 --- a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/Application.java +++ b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/Application.java @@ -65,23 +65,25 @@ public static void main(final String[] args) } @Autowired - private MDEventListener eventListener; + private MaterialEventService eventService; @Autowired - private MaterialEventService eventService; + private MDEventListener mdEventListener; @Bean @Profile("!test") public Adempiere adempiere() { // as of right now, we are not interested in loading any model validator whatsoever within this service + // therefore we don't e.g. have to deal with the async-processor. It just won't be started. ModelValidationEngine.setInitEntityTypes(Collections.emptyList()); final Adempiere adempiere = Env.getSingleAdempiereInstance(); adempiere.setApplicationContext(applicationContext); adempiere.startup(RunMode.BACKEND); - eventService.registerListener(eventListener); + eventService.registerListener(mdEventListener); + eventService.subscribeToEventBus(); return adempiere; } diff --git a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/Candidate.java b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/Candidate.java index 0b4c8b8a074..ad4ae3e7927 100644 --- a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/Candidate.java +++ b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/Candidate.java @@ -5,6 +5,7 @@ import org.adempiere.util.lang.impl.TableRecordReference; +import de.metas.material.dispo.model.X_MD_Candidate; import lombok.Builder; import lombok.Data; import lombok.NonNull; @@ -37,22 +38,30 @@ @Wither public class Candidate { + /** + * Please keep in sync with the values of {@link X_MD_Candidate#MD_CANDIDATE_TYPE_AD_Reference_ID} + */ public enum Type { DEMAND, SUPPLY, STOCK }; /** - * the supply type is relevant if the candidate's type is {@link Type#SUPPLY}. - * - * @author metas-dev - * + * Please keep in sync with the values of {@link X_MD_Candidate#MD_CANDIDATE_SUBTYPE_AD_Reference_ID} */ public enum SubType { DISTRIBUTION, PRODUCTION, RECEIPT, SHIPMENT }; + /** + * Please keep in sync with the values of {@link X_MD_Candidate#MD_CANDIDATE_STATUS_AD_Reference_ID} + */ + public enum Status + { + doc_planned, doc_created, doc_completed, doc_closed, unexpected + } + @NonNull private final Integer orgId; @@ -60,7 +69,7 @@ public enum SubType private final Integer productId; private final Integer attributeSetInstanceId; - + @NonNull private final Integer warehouseId; @@ -80,6 +89,8 @@ public enum SubType */ private final SubType subType; + private final Status status; + private final TableRecordReference reference; private final Integer id; @@ -95,6 +106,11 @@ public enum SubType */ private final ProductionCandidateDetail productionDetail; + /** + * Used for additional infos if this candidate relates to particular demand + */ + private final DemandCandidateDetail demandDetail; + /** * The projected date at which we expect this candidate's {@link #getQuantity()}. */ diff --git a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/CandidateChangeHandler.java b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/CandidateChangeHandler.java index d2283170208..c5c9e61f549 100644 --- a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/CandidateChangeHandler.java +++ b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/CandidateChangeHandler.java @@ -4,6 +4,7 @@ import java.util.Date; import java.util.List; import java.util.Optional; +import java.util.function.Supplier; import org.adempiere.util.Check; import org.adempiere.util.lang.impl.TableRecordReference; @@ -15,6 +16,7 @@ import de.metas.material.dispo.Candidate.Type; import de.metas.material.dispo.CandidatesSegment.DateOperator; +import de.metas.material.event.EventDescr; import de.metas.material.event.MaterialDemandEvent; import de.metas.material.event.MaterialDescriptor; import de.metas.material.event.MaterialEventService; @@ -54,8 +56,7 @@ public class CandidateChangeHandler public CandidateChangeHandler( @NonNull final CandidateRepository candidateRepository, @NonNull final CandidateFactory candidateFactory, - @NonNull final MaterialEventService materialEventService - ) + @NonNull final MaterialEventService materialEventService) { this.candidateRepository = candidateRepository; this.candidateFactory = candidateFactory; @@ -82,7 +83,7 @@ public Candidate onDemandCandidateNewOrChange(@NonNull final Candidate demandCan { Preconditions.checkArgument(demandCandidate.getType() == Type.DEMAND, "Given parameter 'demandCandidate' has type=%s; demandCandidate=%s", demandCandidate.getType(), demandCandidate); - final Candidate demandCandidateWithId = candidateRepository.addOrReplace(demandCandidate); + final Candidate demandCandidateWithId = candidateRepository.addOrUpdate(demandCandidate); if (demandCandidateWithId.getQuantity().signum() == 0) { @@ -93,7 +94,7 @@ public Candidate onDemandCandidateNewOrChange(@NonNull final Candidate demandCan // this is the seqno which the new stock candidate shall get according to the demand candidate final int expectedStockSeqNo = demandCandidateWithId.getSeqNo() + 1; - final Candidate stockWithDemand = updateStock(demandCandidate + final Candidate stockWithDemand = addOrUpdateStock(demandCandidate .withSeqNo(expectedStockSeqNo) .withQuantity(demandCandidateWithId.getQuantity().negate()) .withParentId(demandCandidateWithId.getId())); @@ -106,7 +107,7 @@ public Candidate onDemandCandidateNewOrChange(@NonNull final Candidate demandCan // keep it and in turn update the demandCandidate's seqNo accordingly demandCandidateToReturn = demandCandidate .withSeqNo(stockWithDemand.getSeqNo() - 1); - candidateRepository.addOrReplace(demandCandidateToReturn); + candidateRepository.addOrUpdate(demandCandidateToReturn); } else { @@ -117,8 +118,11 @@ public Candidate onDemandCandidateNewOrChange(@NonNull final Candidate demandCan { // there would be no more stock left, so // notify whoever is in charge that we have a demand to balance + final int orderLineId = demandCandidate.getDemandDetail() == null ? 0 : demandCandidate.getDemandDetail().getOrderLineId(); + final MaterialDemandEvent materialDemandEvent = MaterialDemandEvent .builder() + .eventDescr(new EventDescr()) .descr(MaterialDescriptor.builder() .orgId(demandCandidate.getOrgId()) .productId(demandCandidate.getProductId()) @@ -127,6 +131,7 @@ public Candidate onDemandCandidateNewOrChange(@NonNull final Candidate demandCan .warehouseId(demandCandidate.getWarehouseId()) .build()) .reference(demandCandidate.getReference()) + .orderLineId(orderLineId) .build(); materialEventService.fireEvent(materialDemandEvent); @@ -148,21 +153,39 @@ public Candidate onSupplyCandidateNewOrChange(@NonNull final Candidate supplyCan Preconditions.checkArgument(supplyCandidate.getType() == Type.SUPPLY, "Given parameter 'supplyCandidate' has type=%s; supplyCandidate=%s", supplyCandidate.getType(), supplyCandidate); // store the supply candidate and get both it's ID and qty-delta - final Candidate supplyCandidateDeltaWithId = candidateRepository.addOrReplace(supplyCandidate); + final Candidate supplyCandidateDeltaWithId = candidateRepository.addOrUpdate(supplyCandidate); if (supplyCandidateDeltaWithId.getQuantity().signum() == 0) { return supplyCandidateDeltaWithId; // nothing to do } - // update the stock with the delta - final Candidate parentStockCandidateWithId = updateStock(supplyCandidateDeltaWithId - .withSeqNo(null) // don't provide the supply's SeqNo, because there might already be a stock record which we might override; plus, the supply's seqNo shall depend on the stock's anyways - ); + final Candidate parentStockCandidateWithId; + if (supplyCandidateDeltaWithId.getParentIdNotNull() > 0) + { + // this supply candidate is not new and already has a stock candidate as its parent + parentStockCandidateWithId = updateStock( + supplyCandidateDeltaWithId, + () -> { + // don't check if we might create a new stock candidate, because we know we don't. Get the one that already exists and just update its quantity + final Candidate stockCandidate = candidateRepository.retrieve(supplyCandidateDeltaWithId.getParentId()); + return candidateRepository.updateQty( + stockCandidate.withQuantity( + stockCandidate.getQuantity().add(supplyCandidateDeltaWithId.getQuantity()))); + }); + } + else + { + // update (or add) the stock with the delta + parentStockCandidateWithId = addOrUpdateStock(supplyCandidateDeltaWithId + // but don't provide the supply's SeqNo, because there might already be a stock record which we might override (even if the supply candidate is not yet linked to it); + // plus, the supply's seqNo shall depend on the stock's anyways + .withSeqNo(null)); + } // set the stock candidate as parent for the supply candidate // the return value would have qty=0, but in the repository we updated the parent-ID - candidateRepository.addOrReplace( + candidateRepository.addOrUpdate( supplyCandidate .withParentId(parentStockCandidateWithId.getId()) .withSeqNo(parentStockCandidateWithId.getSeqNo() + 1)); @@ -177,9 +200,32 @@ public Candidate onSupplyCandidateNewOrChange(@NonNull final Candidate supplyCan // now has -21 } - public void onCandidateDelete(@NonNull final TableRecordReference recordReference) + private Candidate updateStock( + @NonNull final Candidate relatedCanidateWithDelta, + @NonNull final Supplier stockCandidateToUpdate) { - candidateRepository.deleteForReference(recordReference); + final Optional previousCandidate = candidateRepository.retrieve(relatedCanidateWithDelta); + + final Candidate persistedStockCandidate = stockCandidateToUpdate.get(); + + final BigDecimal delta; + if (previousCandidate.isPresent()) + { + // there was already a persisted candidate. This means that the addOrReplace already did the work of providing our delta between the old and the current status. + delta = persistedStockCandidate.getQuantity(); + } + else + { + // there was no persisted candidate, so we basically propagate the full qty (positive or negative) of the given candidate upwards + delta = relatedCanidateWithDelta.getQuantity(); + } + applyDeltaToLaterStockCandidates( + relatedCanidateWithDelta.getProductId(), + relatedCanidateWithDelta.getWarehouseId(), + relatedCanidateWithDelta.getDate(), + persistedStockCandidate.getGroupId(), + delta); + return persistedStockCandidate; } /** @@ -193,33 +239,23 @@ public void onCandidateDelete(@NonNull final TableRecordReference recordReferenc * The candidate will have an ID and its quantity will not be a delta, but the "absolute" projected quantity at the given time.
    * Note: this method does not establish a parent-child relationship between any two records */ - public Candidate updateStock(@NonNull final Candidate candidate) + public Candidate addOrUpdateStock(@NonNull final Candidate candidate) { - final Optional previousCandidate = candidateRepository.retrieve(candidate); + return updateStock( + candidate, + () -> { + final Candidate stockCandidateToPersist = candidateFactory.createStockCandidate(candidate); - final Candidate stockCandidateToPersist = candidateFactory.createStockCandidate(candidate); + final boolean preserveExistingSeqNo = true; // there there is a stock record with a seqNo, then don't override it, because we will need to adapt to it in order to put our new data into the right sequence. + final Candidate persistedStockCandidate = candidateRepository.addOrUpdate(stockCandidateToPersist, preserveExistingSeqNo); - final boolean preserveExistingSeqNo = true; // there there is a stock record with a seqNo, then don't override it, because we will need to adapt to it in order to put our new data into the right sequence. - final Candidate persistedStockCandidate = candidateRepository.addOrReplace(stockCandidateToPersist, preserveExistingSeqNo); + return persistedStockCandidate; + }); + } - final BigDecimal delta; - if (previousCandidate.isPresent()) - { - // there was already a persisted candidate. This means that the addOrReplace already did the work of providing our delta between the old and the current status. - delta = persistedStockCandidate.getQuantity(); - } - else - { - // there was no persisted candidate, so we basically propagate the full qty (positive or negative) of the given candidate upwards - delta = candidate.getQuantity(); - } - applyDeltaToLaterStockCandidates( - candidate.getProductId(), - candidate.getWarehouseId(), - candidate.getDate(), - persistedStockCandidate.getGroupId(), - delta); - return persistedStockCandidate; + public void onCandidateDelete(@NonNull final TableRecordReference recordReference) + { + candidateRepository.deleteForReference(recordReference); } /** @@ -254,7 +290,7 @@ public Candidate updateStock(@NonNull final Candidate candidate) for (final Candidate candidate : candidatesToUpdate) { final BigDecimal newQty = candidate.getQuantity().add(delta); - candidateRepository.addOrReplace(candidate + candidateRepository.addOrUpdate(candidate .withQuantity(newQty) .withGroupId(groupId)); } diff --git a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/CandidateFactory.java b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/CandidateFactory.java index 6be7902d294..39e175e0cf3 100644 --- a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/CandidateFactory.java +++ b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/CandidateFactory.java @@ -46,7 +46,12 @@ public CandidateFactory(@NonNull final CandidateRepository candidateRepository) * If there is no such next-younger stock candidate (i.e. if this is the very first stock candidate to be created for the given product and locator), then a quantity of zero is taken. * * @param candidate - * @return + * @return a candidate with + *
      + *
    • type = {@link Type#STOCK}
    • + *
    • qty = qty of the given {@code candidate} plus the next younger candidate's quantity + *
    • groupId of the next younger-candidate (or null if there is none) + *
    */ public Candidate createStockCandidate(@NonNull final Candidate candidate) { diff --git a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/CandidateRepository.java b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/CandidateRepository.java index bf2eb9c2e2f..dd8ebab9a16 100644 --- a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/CandidateRepository.java +++ b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/CandidateRepository.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.Properties; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -16,8 +17,10 @@ import org.adempiere.model.InterfaceWrapperHelper; import org.adempiere.util.Check; import org.adempiere.util.Services; +import org.adempiere.util.lang.IAutoCloseable; import org.adempiere.util.lang.ITableRecordReference; import org.adempiere.util.lang.impl.TableRecordReference; +import org.compiere.model.I_AD_Org; import org.compiere.util.Env; import org.springframework.stereotype.Service; @@ -29,6 +32,7 @@ import de.metas.material.dispo.Candidate.SubType; import de.metas.material.dispo.Candidate.Type; import de.metas.material.dispo.model.I_MD_Candidate; +import de.metas.material.dispo.model.I_MD_Candidate_Demand_Detail; import de.metas.material.dispo.model.I_MD_Candidate_Prod_Detail; import lombok.NonNull; @@ -57,14 +61,14 @@ public class CandidateRepository { /** - * Invokes {@link #addOrReplace(Candidate, boolean)} with {@code preserveExistingSeqNo == false}. + * Invokes {@link #addOrUpdate(Candidate, boolean)} with {@code preserveExistingSeqNo == false}. * * @param candidate * @return */ - public Candidate addOrReplace(@NonNull final Candidate candidate) + public Candidate addOrUpdate(@NonNull final Candidate candidate) { - return addOrReplace(candidate, false); + return addOrUpdate(candidate, false); } /** @@ -78,11 +82,30 @@ public Candidate addOrReplace(@NonNull final Candidate candidate) *
      *
    • the {@code id} of the persisted data record
    • *
    • the {@code groupId} of the persisted data record. This is either the given {@code candidate}'s {@code groupId} or the given candidate's ID (in case the given candiate didn't have a groupId)
    • + *
    • the {@code parentId} of the persisted data record or {@code null} if the persisted record didn't exist or has a parentId of zero. *
    • the {@code seqNo} The rules are similar to groupId, but if there was a persisted {@link I_MD_Candidate} with a different seqno, that different seqno might also be returned, depending on the {@code preserveExistingSeqNo} parameter.
    • *
    • the quantity delta of the persisted data record before the update was made
    • *
    */ - public Candidate addOrReplace(@NonNull final Candidate candidate, final boolean preserveExistingSeqNo) + public Candidate addOrUpdate(@NonNull final Candidate candidate, final boolean preserveExistingSeqNo) + { + // + // make sure that every record we create has the correct AD_Client_ID and AD_Org_ID + final Properties copyCtx = Env.copyCtx(Env.getCtx()); + + final I_AD_Org org = InterfaceWrapperHelper.create(copyCtx, candidate.getOrgId(), I_AD_Org.class, ITrx.TRXNAME_None); + + Env.setContext(copyCtx, Env.CTXNAME_AD_Org_ID, org.getAD_Org_ID()); + Env.setContext(copyCtx, Env.CTXNAME_AD_Client_ID, org.getAD_Client_ID()); + + try (final IAutoCloseable c = Env.switchContext(copyCtx)) + { + return addOrUpdate0(candidate, preserveExistingSeqNo); + } + } + + @VisibleForTesting + Candidate addOrUpdate0(@NonNull final Candidate candidate, final boolean preserveExistingSeqNo) { final Optional oldCandidateRecord = retrieveExact(candidate); @@ -109,17 +132,53 @@ public Candidate addOrReplace(@NonNull final Candidate candidate, final boolean addOrRecplaceProductionDetail(candidate, synchedRecord); } + if (candidate.getDemandDetail() != null) + { + // we do this independently of the type; the demand info might be needed by many records, not just by the "first" demand record + addOrRecplaceDemandDetail(candidate, synchedRecord); + } + + final Integer parentId = synchedRecord.getMD_Candidate_Parent_ID() > 0 ? synchedRecord.getMD_Candidate_Parent_ID() : null; + return candidate .withId(synchedRecord.getMD_Candidate_ID()) + .withParentId(parentId) .withGroupId(synchedRecord.getMD_Candidate_GroupId()) .withSeqNo(synchedRecord.getSeqNo()) .withQuantity(qtyDelta); } - private void addOrRecplaceProductionDetail(final Candidate candidate, final I_MD_Candidate synchedRecord) + /** + * Updates the qty of the given candidate. + * Differs from {@link #addOrUpdate(Candidate)} in that + * no matching id done, and if there is no existing persisted record, then an exception is thrown. Instead, it just updates the underyling persisted record of the given {@code candidateToUpdate}. + * + * + * @param candidateToUpdate the candidate to update. Needs to have {@link Candidate#getId() > 0}. + * + * @return a copy of the given {@code candidateToUpdate} with the quantity being a delta, similar to the return value of {@link #addOrUpdate(Candidate, boolean)}. + */ + public Candidate updateQty(@NonNull final Candidate candidateToUpdate) + { + Preconditions.checkState(candidateToUpdate.getId() != null && candidateToUpdate.getId() > 0, "Parameter 'candidateToUpdate' has Id=%s; candidateToUpdate=%s", candidateToUpdate.getId(), candidateToUpdate); + + final I_MD_Candidate candidateRecord = InterfaceWrapperHelper.create(Env.getCtx(), candidateToUpdate.getId(), I_MD_Candidate.class, ITrx.TRXNAME_ThreadInherited); + + final BigDecimal oldQty = candidateRecord.getQty(); + candidateRecord.setQty(candidateToUpdate.getQuantity()); + InterfaceWrapperHelper.save(candidateRecord); + + final BigDecimal qtyDelta = candidateToUpdate.getQuantity().subtract(oldQty); + + return candidateToUpdate.withQuantity(qtyDelta); + } + + private void addOrRecplaceProductionDetail( + @NonNull final Candidate candidate, + @NonNull final I_MD_Candidate synchedRecord) { final I_MD_Candidate_Prod_Detail detailRecordToUpdate; - final I_MD_Candidate_Prod_Detail existingDetail = retrieveProductiondetail(synchedRecord); + final I_MD_Candidate_Prod_Detail existingDetail = retrieveProductionDetail(synchedRecord); if (existingDetail == null) { detailRecordToUpdate = InterfaceWrapperHelper.newInstance(I_MD_Candidate_Prod_Detail.class, synchedRecord); @@ -141,9 +200,10 @@ private void addOrRecplaceProductionDetail(final Candidate candidate, final I_MD InterfaceWrapperHelper.save(detailRecordToUpdate); } - private I_MD_Candidate_Prod_Detail retrieveProductiondetail(final I_MD_Candidate synchedRecord) + private I_MD_Candidate_Prod_Detail retrieveProductionDetail(@NonNull final I_MD_Candidate synchedRecord) { - final I_MD_Candidate_Prod_Detail existingDetail = Services.get(IQueryBL.class).createQueryBuilder(I_MD_Candidate_Prod_Detail.class) + final IQueryBL queryBL = Services.get(IQueryBL.class); + final I_MD_Candidate_Prod_Detail existingDetail = queryBL.createQueryBuilder(I_MD_Candidate_Prod_Detail.class) .addOnlyActiveRecordsFilter() .addEqualsFilter(I_MD_Candidate_Prod_Detail.COLUMN_MD_Candidate_ID, synchedRecord.getMD_Candidate_ID()) .create() @@ -151,6 +211,42 @@ private I_MD_Candidate_Prod_Detail retrieveProductiondetail(final I_MD_Candidate return existingDetail; } + private void addOrRecplaceDemandDetail( + @NonNull final Candidate candidate, + @NonNull final I_MD_Candidate synchedRecord) + { + if (candidate.getDemandDetail() == null || candidate.getDemandDetail().getOrderLineId() <= 0) + { + return; // nothing to do + } + + final I_MD_Candidate_Demand_Detail detailRecordToUpdate; + final I_MD_Candidate_Demand_Detail existingDetail = retrieveDemandDetail(synchedRecord); + if (existingDetail == null) + { + detailRecordToUpdate = InterfaceWrapperHelper.newInstance(I_MD_Candidate_Demand_Detail.class, synchedRecord); + detailRecordToUpdate.setMD_Candidate(synchedRecord); + } + else + { + detailRecordToUpdate = existingDetail; + } + final DemandCandidateDetail demandDetail = candidate.getDemandDetail(); + detailRecordToUpdate.setC_OrderLine_ID(demandDetail.getOrderLineId()); + InterfaceWrapperHelper.save(detailRecordToUpdate); + } + + private I_MD_Candidate_Demand_Detail retrieveDemandDetail(@NonNull final I_MD_Candidate synchedRecord) + { + final IQueryBL queryBL = Services.get(IQueryBL.class); + final I_MD_Candidate_Demand_Detail existingDetail = queryBL.createQueryBuilder(I_MD_Candidate_Demand_Detail.class) + .addOnlyActiveRecordsFilter() + .addEqualsFilter(I_MD_Candidate_Demand_Detail.COLUMN_MD_Candidate_ID, synchedRecord.getMD_Candidate_ID()) + .create() + .firstOnly(I_MD_Candidate_Demand_Detail.class); // TODO we don't yet have a UC in place.. + return existingDetail; + } + public Optional retrieve(@NonNull final Candidate candidate) { return fromCandidateRecord(retrieveExact(candidate)); @@ -198,7 +294,10 @@ public List retrieveGroup(final Integer groupId) *
  • warehouse
  • *
  • product
  • *
  • date
  • - *
  • tableId and record?
  • + *
  • tableId and record (only if set)
  • + *
  • demand details
  • + *
  • production details: if {@link Candidate#getProductionDetail()} is {@code null}, then only records without product detail are selected. + * If it's not null and either a product plan ID or BOM line ID is set, then only records with a matching detail record are selected. Note that those two don't change (like pporder ID and pporder BOM line ID which can change for zero to an actual reference)
  • * * * @param candidate @@ -224,6 +323,61 @@ public List retrieveGroup(final Integer groupId) builder.addEqualsFilter(I_MD_Candidate.COLUMN_Record_ID, referencedRecord.getRecord_ID()); } + final DemandCandidateDetail demandDetail = candidate.getDemandDetail(); + if (demandDetail != null && demandDetail.getOrderLineId() != 0) + { + final IQueryBuilder demandDetailsSubQueryBuilder = queryBL + .createQueryBuilder(I_MD_Candidate_Demand_Detail.class) + .addOnlyActiveRecordsFilter(); + + if (demandDetail.getOrderLineId() == DemandCandidateDetail.NO_ORDERLINE_ID) + { + builder.addNotInSubQueryFilter(I_MD_Candidate.COLUMN_MD_Candidate_ID, + I_MD_Candidate_Demand_Detail.COLUMN_MD_Candidate_ID, + demandDetailsSubQueryBuilder.create()); + } + else if (demandDetail.getOrderLineId() > 0) + { + demandDetailsSubQueryBuilder + .addEqualsFilter(I_MD_Candidate_Demand_Detail.COLUMN_C_OrderLine_ID, demandDetail.getOrderLineId()); + + builder.addInSubQueryFilter(I_MD_Candidate.COLUMN_MD_Candidate_ID, + I_MD_Candidate_Demand_Detail.COLUMN_MD_Candidate_ID, + demandDetailsSubQueryBuilder.create()); + } + } + + { + final ProductionCandidateDetail productionDetail = candidate.getProductionDetail(); + + final IQueryBuilder productDetailSubQueryBuilder = queryBL + .createQueryBuilder(I_MD_Candidate_Prod_Detail.class) + .addOnlyActiveRecordsFilter(); + + if (productionDetail == null) + { + builder.addNotInSubQueryFilter(I_MD_Candidate.COLUMN_MD_Candidate_ID, I_MD_Candidate_Prod_Detail.COLUMN_MD_Candidate_ID, productDetailSubQueryBuilder.create()); + } + else + { + boolean doFilter = false; + if (productionDetail.getProductPlanningId() > 0) + { + productDetailSubQueryBuilder.addEqualsFilter(I_MD_Candidate_Prod_Detail.COLUMN_PP_Product_Planning_ID, productionDetail.getProductPlanningId()); + doFilter = true; + } + if (productionDetail.getProductBomLineId() > 0) + { + productDetailSubQueryBuilder.addEqualsFilter(I_MD_Candidate_Prod_Detail.COLUMN_PP_Product_BOMLine_ID, productionDetail.getProductBomLineId()); + doFilter = true; + } + if (doFilter) + { + builder.addInSubQueryFilter(I_MD_Candidate.COLUMN_MD_Candidate_ID, I_MD_Candidate_Prod_Detail.COLUMN_MD_Candidate_ID, productDetailSubQueryBuilder.create()); + } + } + } + final I_MD_Candidate candidateRecord = builder .create() .firstOnly(I_MD_Candidate.class); // note that we have a UC to make sure there is just one @@ -292,6 +446,11 @@ private I_MD_Candidate syncToRecord( candidateRecordToUse.setMD_Candidate_GroupId(candidate.getGroupId()); } + if (candidate.getStatus() != null) + { + candidateRecordToUse.setMD_Candidate_Status(candidate.getStatus().toString()); + } + return candidateRecordToUse; } @@ -343,7 +502,7 @@ private Optional fromCandidateRecord(final Optional c } if (subType == SubType.PRODUCTION) { - final I_MD_Candidate_Prod_Detail productiondetail = retrieveProductiondetail(candidateRecord); + final I_MD_Candidate_Prod_Detail productiondetail = retrieveProductionDetail(candidateRecord); if (productiondetail != null) { builder.productionDetail(ProductionCandidateDetail.builder() @@ -359,6 +518,14 @@ private Optional fromCandidateRecord(final Optional c } } + final I_MD_Candidate_Demand_Detail demandDetail = retrieveDemandDetail(candidateRecord); + if (demandDetail != null) + { + builder.demandDetail(DemandCandidateDetail.builder() + .orderLineId(demandDetail.getC_OrderLine_ID()) + .build()); + } + return Optional.of(builder.build()); } @@ -372,7 +539,12 @@ public Optional retrieveLatestMatch(@NonNull final CandidatesSegment final IQueryBuilder builder = mkQueryBuilder(segment); final I_MD_Candidate candidateRecord = builder - .orderBy().addColumn(I_MD_Candidate.COLUMNNAME_DateProjected, false).endOrderBy() + .orderBy() + // there can be many stock candidates with the same DateProjected, because e.g. a to of sales orders can all have the same promised date and time + // therefore we need to filter by both dateprojected and md-candidate-id + .addColumn(I_MD_Candidate.COLUMNNAME_DateProjected, false) + .addColumn(I_MD_Candidate.COLUMNNAME_MD_Candidate_ID, false) + .endOrderBy() .create() .first(); @@ -486,5 +658,4 @@ private IQueryBuilder mkReferencedRecordFilter(final TableRecord .addEqualsFilter(I_MD_Candidate.COLUMN_AD_Table_ID, reference.getAD_Table_ID()) .addEqualsFilter(I_MD_Candidate.COLUMN_Record_ID, reference.getRecord_ID()); } - } diff --git a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/CandidateService.java b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/CandidateService.java index 9d9fbc4d1e8..cbd31fa93f4 100644 --- a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/CandidateService.java +++ b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/CandidateService.java @@ -1,14 +1,17 @@ package de.metas.material.dispo; -import java.time.Instant; import java.util.List; +import org.springframework.stereotype.Service; + import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import de.metas.material.dispo.Candidate.SubType; import de.metas.material.dispo.Candidate.Type; -import de.metas.material.event.ProductionOrderRequested; +import de.metas.material.event.EventDescr; +import de.metas.material.event.MaterialEventService; +import de.metas.material.event.PPOrderRequestedEvent; import de.metas.material.event.pporder.PPOrder; import de.metas.material.event.pporder.PPOrder.PPOrderBuilder; import de.metas.material.event.pporder.PPOrderLine; @@ -35,13 +38,17 @@ * . * #L% */ - +@Service public class CandidateService { private final CandidateRepository candidateRepository; + private final MaterialEventService materialEventService; - public CandidateService(@NonNull final CandidateRepository candidateRepository) + public CandidateService( + @NonNull final CandidateRepository candidateRepository, + @NonNull final MaterialEventService materialEventService) { + this.materialEventService = materialEventService; this.candidateRepository = candidateRepository; } @@ -66,14 +73,21 @@ public void requestPPOrder(@NonNull final Integer groupId) } /** - * + * * @param group a non-empty list of candidates that all have {@link SubType#PRODUCTION}, * all have the same {@link Candidate#getGroupId()} * and all have appropriate not-null {@link Candidate#getProductionDetail()}s. * @return */ + + private void requestProductionOrder(@NonNull final List group) + { + final PPOrderRequestedEvent ppOrderRequestEvent = createRequestEvent(group); + materialEventService.fireEvent(ppOrderRequestEvent); + } + @VisibleForTesting - ProductionOrderRequested requestProductionOrder(@NonNull final List group) + PPOrderRequestedEvent createRequestEvent(final List group) { Preconditions.checkArgument(!group.isEmpty(), "Param 'group' is an empty list"); @@ -81,6 +95,11 @@ ProductionOrderRequested requestProductionOrder(@NonNull final List g for (final Candidate groupMember : group) { + if (groupMember.getDemandDetail() != null && groupMember.getDemandDetail().getOrderLineId() > 0) + { + ppOrderBuilder = ppOrderBuilder.orderLineId(groupMember.getDemandDetail().getOrderLineId()); + } + final ProductionCandidateDetail prodDetail = groupMember.getProductionDetail(); if (prodDetail.getPlantId() > 0) { @@ -118,9 +137,10 @@ ProductionOrderRequested requestProductionOrder(@NonNull final List g .build()); } } - return ProductionOrderRequested.builder() + return PPOrderRequestedEvent.builder() + .eventDescr(new EventDescr()) + .eventDescr(new EventDescr()) .ppOrder(ppOrderBuilder.build()) - .when(Instant.now()) .reference(group.get(0).getReference()) .build(); } diff --git a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/DemandCandidateDetail.java b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/DemandCandidateDetail.java new file mode 100644 index 00000000000..df0f4905094 --- /dev/null +++ b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/DemandCandidateDetail.java @@ -0,0 +1,37 @@ +package de.metas.material.dispo; + +import lombok.Builder; +import lombok.Data; + +/* + * #%L + * metasfresh-material-dispo + * %% + * Copyright (C) 2017 metas GmbH + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +@Data +@Builder +public class DemandCandidateDetail +{ + /** + * This ID indicates that the demand candidate explicitly specifies "no order line id". All other values less or equal zero mean "i don't care". + */ + public static final int NO_ORDERLINE_ID = -99; + + private final int orderLineId; +} diff --git a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/event/DistributionPlanEventHandler.java b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/event/DistributionPlanEventHandler.java new file mode 100644 index 00000000000..1a03fe055b3 --- /dev/null +++ b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/event/DistributionPlanEventHandler.java @@ -0,0 +1,125 @@ +package de.metas.material.dispo.event; + +import org.springframework.stereotype.Service; + +import de.metas.material.dispo.Candidate; +import de.metas.material.dispo.Candidate.SubType; +import de.metas.material.dispo.Candidate.Type; +import de.metas.material.dispo.CandidateChangeHandler; +import de.metas.material.dispo.CandidateRepository; +import de.metas.material.dispo.DemandCandidateDetail; +import de.metas.material.dispo.event.SupplyProposalEvaluator.SupplyProposal; +import de.metas.material.event.DistributionPlanEvent; +import de.metas.material.event.MaterialDescriptor; +import lombok.NonNull; + +/* + * #%L + * metasfresh-material-dispo + * %% + * Copyright (C) 2017 metas GmbH + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +@Service +public class DistributionPlanEventHandler +{ + private final CandidateRepository candidateRepository; + private final SupplyProposalEvaluator supplyProposalEvaluator; + private CandidateChangeHandler candidateChangeHandler; + + public DistributionPlanEventHandler( + @NonNull final CandidateRepository candidateRepository, + @NonNull final CandidateChangeHandler candidateChangeHandler, + @NonNull final SupplyProposalEvaluator supplyProposalEvaluator) + { + this.candidateChangeHandler = candidateChangeHandler; + this.candidateRepository = candidateRepository; + this.supplyProposalEvaluator = supplyProposalEvaluator; + } + + void handleDistributionPlanEvent(final DistributionPlanEvent event) + { + final MaterialDescriptor materialDescr = event.getMaterialDescr(); + + final SupplyProposal proposal = SupplyProposal.builder() + .date(event.getDistributionStart()) + .productId(materialDescr.getProductId()) + .destWarehouseId(materialDescr.getWarehouseId()) + .sourceWarehouseId(event.getFromWarehouseId()) + .build(); + if (!supplyProposalEvaluator.evaluateSupply(proposal)) + { + // 'supplyProposalEvaluator' told us to ignore the given supply candidate. + // the reason for this could be that it found an already existing distribution plan pointing in the other direction. + // so instead of playing an infinite game of ping-ping with the material-planning component, it ignored the given 'event' + // and leave it to the user to come up with a great idea. + return; + } + + final Candidate supplyCandidate = Candidate.builder() + .type(Type.SUPPLY) + .subType(SubType.DISTRIBUTION) + .date(materialDescr.getDate()) + .orgId(materialDescr.getOrgId()) + .productId(materialDescr.getProductId()) + .quantity(materialDescr.getQty()) + .warehouseId(materialDescr.getWarehouseId()) + .reference(event.getReference()) + .demandDetail(DemandCandidateDetail.builder() + .orderLineId(event.getOrderLineId()) + .build()) + .build(); + + final Candidate supplyCandidateWithId = candidateChangeHandler.onSupplyCandidateNewOrChange(supplyCandidate); + if (supplyCandidateWithId.getQuantity().signum() == 0) + { + // nothing was added as supply in the destination warehouse, so there is no demand to register either + return; + } + + // we expect the demand candidate to go with the supplyCandidates SeqNo + 1, + // *but* it might also be the case that the demandCandidate attaches to an existing stock and in that case would need to get another SeqNo + final int expectedSeqNoForDemandCandidate = supplyCandidateWithId.getSeqNo() + 1; + + final Candidate demandCandidate = supplyCandidate + .withType(Type.DEMAND) + .withSubType(SubType.DISTRIBUTION) + .withGroupId(supplyCandidateWithId.getGroupId()) + .withParentId(supplyCandidateWithId.getId()) + .withQuantity(supplyCandidateWithId.getQuantity()) // what was added as supply in the destination warehouse needs to be registered as demand in the source warehouse + .withDate(event.getDistributionStart()) + .withSeqNo(expectedSeqNoForDemandCandidate) + .withWarehouseId(event.getFromWarehouseId()); + + // this might cause 'candidateChangeHandler' to trigger another event + final Candidate demandCandidateWithId = candidateChangeHandler.onDemandCandidateNewOrChange(demandCandidate); + if (expectedSeqNoForDemandCandidate == demandCandidateWithId.getSeqNo()) + { + return; // we are done + } + + // update/override the SeqNo of both supplyCandidate and supplyCandidate's stock candidate. + candidateRepository.addOrUpdate(supplyCandidateWithId + .withSeqNo(demandCandidateWithId.getSeqNo() - 1), + false); + + candidateRepository.addOrUpdate(candidateRepository + .retrieve(supplyCandidateWithId.getParentId()) + .withSeqNo(demandCandidateWithId.getSeqNo() - 2), + false); + } +} diff --git a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/event/EventStoreListener.java b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/event/EventStoreListener.java new file mode 100644 index 00000000000..b6ef6e2d403 --- /dev/null +++ b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/event/EventStoreListener.java @@ -0,0 +1,47 @@ +package de.metas.material.dispo.event; + +import java.sql.Timestamp; + +import org.adempiere.model.InterfaceWrapperHelper; + +import de.metas.material.dispo.model.I_MD_EventStore; +import de.metas.material.event.MaterialEvent; +import de.metas.material.event.MaterialEventListener; + +/* + * #%L + * metasfresh-material-dispo + * %% + * Copyright (C) 2017 metas GmbH + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +public class EventStoreListener implements MaterialEventListener +{ + + @Override + public void onEvent(MaterialEvent event) + { + final I_MD_EventStore eventStoreRecord = InterfaceWrapperHelper.newInstance(I_MD_EventStore.class); + + eventStoreRecord.setEventTime(Timestamp.from(event.getEventDescr().getWhen())); + + // TODO Auto-generated method stub + + } + +} diff --git a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/event/MDEventListener.java b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/event/MDEventListener.java index bb128d5a321..cfe117cd00a 100644 --- a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/event/MDEventListener.java +++ b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/event/MDEventListener.java @@ -1,14 +1,13 @@ package de.metas.material.dispo.event; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import de.metas.material.dispo.Candidate; import de.metas.material.dispo.Candidate.SubType; import de.metas.material.dispo.Candidate.Type; import de.metas.material.dispo.CandidateChangeHandler; -import de.metas.material.dispo.CandidateRepository; -import de.metas.material.dispo.ProductionCandidateDetail; -import de.metas.material.dispo.event.SupplyProposalEvaluator.SupplyProposal; +import de.metas.material.dispo.DemandCandidateDetail; import de.metas.material.event.DistributionPlanEvent; import de.metas.material.event.MaterialDescriptor; import de.metas.material.event.MaterialEvent; @@ -17,8 +16,6 @@ import de.metas.material.event.ReceiptScheduleEvent; import de.metas.material.event.ShipmentScheduleEvent; import de.metas.material.event.TransactionEvent; -import de.metas.material.event.pporder.PPOrder; -import de.metas.material.event.pporder.PPOrderLine; import lombok.NonNull; /* @@ -43,22 +40,24 @@ * #L% */ @Service +@Lazy public class MDEventListener implements MaterialEventListener { private final CandidateChangeHandler candidateChangeHandler; - private final CandidateRepository candidateRepository; + private final ProductionPlanEventHandler productionPlanEventHandler; - private final SupplyProposalEvaluator supplyProposalEvaluator; + private DistributionPlanEventHandler distributionPlanEventHandler; - public MDEventListener(@NonNull final CandidateChangeHandler candidateChangeHandler, - @NonNull final CandidateRepository candidateRepository, - @NonNull final SupplyProposalEvaluator supplyProposalEvaluator) + public MDEventListener( + @NonNull final CandidateChangeHandler candidateChangeHandler, + @NonNull final DistributionPlanEventHandler distributionPlanEventHandler, + @NonNull final ProductionPlanEventHandler productionPlanEventHandler) { + this.distributionPlanEventHandler = distributionPlanEventHandler; + this.productionPlanEventHandler = productionPlanEventHandler; this.candidateChangeHandler = candidateChangeHandler; - this.candidateRepository = candidateRepository; - this.supplyProposalEvaluator = supplyProposalEvaluator; } @Override @@ -78,139 +77,14 @@ else if (event instanceof ShipmentScheduleEvent) } else if (event instanceof DistributionPlanEvent) { - handleDistributionPlanEvent((DistributionPlanEvent)event); + distributionPlanEventHandler.handleDistributionPlanEvent((DistributionPlanEvent)event); } else if (event instanceof ProductionPlanEvent) { - handleProductionPlanEvent((ProductionPlanEvent)event); + productionPlanEventHandler.handleProductionPlanEvent((ProductionPlanEvent)event); } } - private void handleProductionPlanEvent(final ProductionPlanEvent event) - { - final PPOrder ppOrder = event.getPpOrder(); - - // ppOrder.getProductBomUomId(); // TODO - - final Candidate supplyCandidate = Candidate.builder() - .type(Type.SUPPLY) - .subType(SubType.PRODUCTION) - .date(ppOrder.getDatePromised()) - .orgId(ppOrder.getOrgId()) - .productId(ppOrder.getProductId()) - - .quantity(ppOrder.getQuantity()) - .warehouseId(ppOrder.getWarehouseId()) - .reference(event.getReference()) - .productionDetail(ProductionCandidateDetail.builder() - .plantId(ppOrder.getPlantId()) - .productPlanningId(ppOrder.getProductPlanningId()) - .ppOrderId(ppOrder.getPpOrderId()) - .ppOrderDocStatus(ppOrder.getDocStatus()) - .build()) - .build(); - - // this might cause 'candidateChangeHandler' to trigger another event - final Candidate candidateWithGroupId = candidateChangeHandler.onSupplyCandidateNewOrChange(supplyCandidate); - - for (final PPOrderLine ppOrderLine : ppOrder.getLines()) - { - final Candidate lineCandidate = Candidate.builder() - .type(ppOrderLine.isReceipt() ? Type.SUPPLY : Type.DEMAND) - .subType(SubType.PRODUCTION) - - .groupId(candidateWithGroupId.getGroupId()) - .seqNo(candidateWithGroupId.getSeqNo() + 1) - - .date(ppOrderLine.isReceipt() ? ppOrder.getDatePromised() : ppOrder.getDateStartSchedule()) - .orgId(ppOrder.getOrgId()) - .productId(ppOrderLine.getProductId()) - .attributeSetInstanceId(ppOrderLine.getAttributeSetInstanceId()) - .quantity(ppOrderLine.getQtyRequired()) - .warehouseId(ppOrder.getWarehouseId()) - .reference(event.getReference()) - .productionDetail(ProductionCandidateDetail.builder() - .productBomLineId(ppOrderLine.getProductBomLineId()) - .description(ppOrderLine.getDescription()) - .ppOrderId(ppOrder.getPpOrderId()) - .ppOrderDocStatus(ppOrder.getDocStatus()) - .ppOrderLineId(ppOrderLine.getPpOrderLineId()) - .build()) - .build(); - - candidateChangeHandler.onCandidateNewOrChange(lineCandidate); - } - } - - private void handleDistributionPlanEvent(final DistributionPlanEvent event) - { - final MaterialDescriptor materialDescr = event.getMaterialDescr(); - - final SupplyProposal proposal = SupplyProposal.builder() - .date(event.getDistributionStart()) - .productId(materialDescr.getProductId()) - .destWarehouseId(materialDescr.getWarehouseId()) - .sourceWarehouseId(event.getFromWarehouseId()) - .build(); - if (!supplyProposalEvaluator.evaluateSupply(proposal)) - { - // 'supplyProposalEvaluator' told us to ignore the given supply candidate. - // the reason for this could be that it found an already existing distribution plan pointing in the other direction. - // so instead of playing an infinite game of ping-ping with the material-planning component, it ignored the given 'event' - // and leave it to the user to come up with a great idea. - return; - } - - final Candidate supplyCandidate = Candidate.builder() - .type(Type.SUPPLY) - .subType(SubType.DISTRIBUTION) - .date(materialDescr.getDate()) - .orgId(materialDescr.getOrgId()) - .productId(materialDescr.getProductId()) - .quantity(materialDescr.getQty()) - .warehouseId(materialDescr.getWarehouseId()) - .reference(event.getReference()) - .build(); - - final Candidate supplyCandidateWithId = candidateChangeHandler.onSupplyCandidateNewOrChange(supplyCandidate); - if (supplyCandidateWithId.getQuantity().signum() == 0) - { - // nothing was added as supply in the destination warehouse, so there is no demand to register either - return; - } - - // we expect the demand candidate to go with the supplyCandidates SeqNo + 1, - // *but* it might also be the case that the demandCandidate attaches to an existing stock and in that case would need to get another SeqNo - final int expectedSeqNoForDemandCandidate = supplyCandidateWithId.getSeqNo() + 1; - - final Candidate demandCandidate = supplyCandidate - .withType(Type.DEMAND) - .withSubType(SubType.DISTRIBUTION) - .withGroupId(supplyCandidateWithId.getGroupId()) - .withParentId(supplyCandidateWithId.getId()) - .withQuantity(supplyCandidateWithId.getQuantity()) // what was added as supply in the destination warehouse needs to be registered as demand in the source warehouse - .withDate(event.getDistributionStart()) - .withSeqNo(expectedSeqNoForDemandCandidate) - .withWarehouseId(event.getFromWarehouseId()); - - // this might cause 'candidateChangeHandler' to trigger another event - final Candidate demandCandidateWithId = candidateChangeHandler.onDemandCandidateNewOrChange(demandCandidate); - if (expectedSeqNoForDemandCandidate == demandCandidateWithId.getSeqNo()) - { - return; // we are done - } - - // update/override the SeqNo of both supplyCandidate and supplyCandidate's stock candidate. - candidateRepository.addOrReplace(supplyCandidateWithId - .withSeqNo(demandCandidateWithId.getSeqNo() - 1), - false); - - candidateRepository.addOrReplace(candidateRepository - .retrieve(supplyCandidateWithId.getParentId()) - .withSeqNo(demandCandidateWithId.getSeqNo() - 2), - false); - } - private void handleTransactionEvent(@NonNull final TransactionEvent event) { if (event.isTransactionDeleted()) @@ -231,7 +105,7 @@ private void handleTransactionEvent(@NonNull final TransactionEvent event) .reference(event.getReference()) .build(); - candidateChangeHandler.updateStock(candidate); + candidateChangeHandler.addOrUpdateStock(candidate); } private void handleReceiptScheduleEvent(@NonNull final ReceiptScheduleEvent event) @@ -277,6 +151,9 @@ private void handleShipmentScheduleEvent(@NonNull final ShipmentScheduleEvent ev .productId(materialDescr.getProductId()) .quantity(materialDescr.getQty()) .reference(event.getReference()) + .demandDetail(DemandCandidateDetail.builder() + .orderLineId(event.getOrderLineId()) + .build()) .build(); candidateChangeHandler.onDemandCandidateNewOrChange(candidate); } diff --git a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/event/ProductionPlanEventHandler.java b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/event/ProductionPlanEventHandler.java new file mode 100644 index 00000000000..74afe371616 --- /dev/null +++ b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/event/ProductionPlanEventHandler.java @@ -0,0 +1,142 @@ +package de.metas.material.dispo.event; + +import org.springframework.stereotype.Service; + +import de.metas.material.dispo.Candidate; +import de.metas.material.dispo.Candidate.Status; +import de.metas.material.dispo.Candidate.SubType; +import de.metas.material.dispo.Candidate.Type; +import de.metas.material.dispo.CandidateChangeHandler; +import de.metas.material.dispo.CandidateService; +import de.metas.material.dispo.DemandCandidateDetail; +import de.metas.material.dispo.ProductionCandidateDetail; +import de.metas.material.event.ProductionPlanEvent; +import de.metas.material.event.pporder.PPOrder; +import de.metas.material.event.pporder.PPOrderLine; +import lombok.NonNull; + +/* + * #%L + * metasfresh-material-dispo + * %% + * Copyright (C) 2017 metas GmbH + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +@Service +public class ProductionPlanEventHandler +{ + private final CandidateChangeHandler candidateChangeHandler; + private final CandidateService candidateService; + + public ProductionPlanEventHandler( + @NonNull final CandidateChangeHandler candidateChangeHandler, + @NonNull final CandidateService candidateService) + { + this.candidateChangeHandler = candidateChangeHandler; + this.candidateService = candidateService; + } + + void handleProductionPlanEvent(final ProductionPlanEvent event) + { + final PPOrder ppOrder = event.getPpOrder(); + + final Candidate.Status candidateStatus; + if (ppOrder.getPpOrderId() <= 0) + { + candidateStatus = Status.doc_planned; + } + else if ("DR".equals(ppOrder.getDocStatus())||"IP".equals(ppOrder.getDocStatus())) + { + candidateStatus = Status.doc_created; + } + else if ("CO".equals(ppOrder.getDocStatus())) + { + candidateStatus = Status.doc_completed; + } + else if ("CL".equals(ppOrder.getDocStatus())) + { + candidateStatus = Status.doc_closed; + } + else + { + candidateStatus = Status.unexpected; + } + + final Candidate supplyCandidate = Candidate.builder() + .type(Type.SUPPLY) + .subType(SubType.PRODUCTION) + .status(candidateStatus) + + .date(ppOrder.getDatePromised()) + .orgId(ppOrder.getOrgId()) + .productId(ppOrder.getProductId()) + .quantity(ppOrder.getQuantity()) + .warehouseId(ppOrder.getWarehouseId()) + .reference(event.getReference()) + .productionDetail(ProductionCandidateDetail.builder() + .plantId(ppOrder.getPlantId()) + .productPlanningId(ppOrder.getProductPlanningId()) + .ppOrderId(ppOrder.getPpOrderId()) + .ppOrderDocStatus(ppOrder.getDocStatus()) + .build()) + .demandDetail(DemandCandidateDetail.builder() + .orderLineId(ppOrder.getOrderLineId()) + .build()) + .build(); + + // this might cause 'candidateChangeHandler' to trigger another event + final Candidate candidateWithGroupId = candidateChangeHandler.onSupplyCandidateNewOrChange(supplyCandidate); + + for (final PPOrderLine ppOrderLine : ppOrder.getLines()) + { + final Candidate lineCandidate = Candidate.builder() + .type(ppOrderLine.isReceipt() ? Type.SUPPLY : Type.DEMAND) + .subType(SubType.PRODUCTION) + .status(candidateStatus) + + .groupId(candidateWithGroupId.getGroupId()) + .seqNo(candidateWithGroupId.getSeqNo() + 1) + + .date(ppOrderLine.isReceipt() ? ppOrder.getDatePromised() : ppOrder.getDateStartSchedule()) + .orgId(ppOrder.getOrgId()) + .productId(ppOrderLine.getProductId()) + .attributeSetInstanceId(ppOrderLine.getAttributeSetInstanceId()) + .quantity(ppOrderLine.getQtyRequired()) + .warehouseId(ppOrder.getWarehouseId()) + .reference(event.getReference()) + .productionDetail(ProductionCandidateDetail.builder() + .productBomLineId(ppOrderLine.getProductBomLineId()) + .description(ppOrderLine.getDescription()) + .ppOrderId(ppOrder.getPpOrderId()) + .ppOrderDocStatus(ppOrder.getDocStatus()) + .ppOrderLineId(ppOrderLine.getPpOrderLineId()) + .build()) + .demandDetail(DemandCandidateDetail.builder() + .orderLineId(ppOrder.getOrderLineId()) + .build()) + .build(); + + // might trigger further demand events + candidateChangeHandler.onCandidateNewOrChange(lineCandidate); + } + + if (ppOrder.isCreatePPOrder()) + { + candidateService.requestPPOrder(candidateWithGroupId.getGroupId()); + } + } +} diff --git a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/event/SupplyProposalEvaluator.java b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/event/SupplyProposalEvaluator.java index 9517d3d8b11..74784e5b332 100644 --- a/de.metas.material/dispo/src/main/java/de/metas/material/dispo/event/SupplyProposalEvaluator.java +++ b/de.metas.material/dispo/src/main/java/de/metas/material/dispo/event/SupplyProposalEvaluator.java @@ -1,7 +1,9 @@ package de.metas.material.dispo.event; import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.springframework.stereotype.Service; @@ -52,9 +54,9 @@ public class SupplyProposalEvaluator public SupplyProposalEvaluator(@NonNull final CandidateRepository candidateRepository) { - this.candidateRepository=candidateRepository; + this.candidateRepository = candidateRepository; } - + /** * For the given {@code proposal}, look for existing demand records which match the proposal's destination and are linked (directly or indirectly, via parent-references) to any supply record matching the proposal's source. *

    @@ -100,7 +102,11 @@ public boolean evaluateSupply(@NonNull final SupplyProposal proposal) final List demands = candidateRepository.retrieveMatches(demandSegment); for (final Candidate demand : demands) { - final Candidate indirectSupplyCandidate = searchRecursive(demand, supplySegment); + final Candidate indirectSupplyCandidate = searchRecursive( + demand, + supplySegment, + new HashSet<>()); + if (indirectSupplyCandidate != null) { return false; @@ -110,33 +116,48 @@ public boolean evaluateSupply(@NonNull final SupplyProposal proposal) return true; } - private Candidate searchRecursive(@NonNull final Candidate candidate, @NonNull final CandidatesSegment searchTarget) + private Candidate searchRecursive( + @NonNull final Candidate currentCandidate, + @NonNull final CandidatesSegment searchTarget, + @NonNull final Set alreadySeen) { - if (searchTarget.matches(candidate)) + if (!alreadySeen.add(currentCandidate)) + { + return null; + } + + if (searchTarget.matches(currentCandidate)) { - return candidate; + return currentCandidate; } - if (candidate.getParentIdNotNull() > 0) + if (currentCandidate.getParentIdNotNull() > 0) { - final Candidate foundSearchTarget = searchRecursive(candidateRepository.retrieve(candidate.getParentId()), searchTarget); + final Candidate foundSearchTarget = searchRecursive( + candidateRepository.retrieve(currentCandidate.getParentId()), + searchTarget, + alreadySeen); if (foundSearchTarget != null) { return foundSearchTarget; } } else /* the "else" is important to avoid a stack overflow error */ - if (candidate.getGroupIdNotNull() > 0) + if (currentCandidate.getGroupIdNotNull() > 0) { - final List group = candidateRepository.retrieveGroup(candidate.getGroupIdNotNull()); + final List group = candidateRepository.retrieveGroup(currentCandidate.getGroupIdNotNull()); for (final Candidate groupMember : group) { - if (groupMember.getId() <= candidate.getId()) + if (groupMember.getId() <= currentCandidate.getId()) { continue; // avoid a stack overflow error } - final Candidate foundSearchTarget = searchRecursive(groupMember, searchTarget); + final Candidate foundSearchTarget = searchRecursive( + groupMember, + searchTarget, + alreadySeen); + if (foundSearchTarget != null) { return foundSearchTarget; diff --git a/de.metas.material/dispo/src/main/resources/application.properties b/de.metas.material/dispo/src/main/resources/application.properties index 15b6d34c406..6eef16d88e8 100644 --- a/de.metas.material/dispo/src/main/resources/application.properties +++ b/de.metas.material/dispo/src/main/resources/application.properties @@ -1,3 +1,8 @@ +# +# use this port on order to not collide with the ports of other metasfresh services that might run in the same box +# +server.port=8283 + # -------------------------------------------------------------------------------- # Build info # -------------------------------------------------------------------------------- @@ -6,6 +11,8 @@ info.build.ciBuildTag=@env.BUILD_TAG@ info.build.ciBuildUrl=@env.BUILD_URL@ info.build.ciJobName=@env.JOB_NAME@ +spring.application.name=metasfresh-material-dispo + # # Logging # diff --git a/de.metas.material/dispo/src/main/sql/postgresql/system/5461090_sys_gh523-metasfresh_add_AD_Process_MD_Candidate_Request_PP_Order.sql b/de.metas.material/dispo/src/main/sql/postgresql/system/5461090_sys_gh523-metasfresh_add_AD_Process_MD_Candidate_Request_PP_Order.sql index 9d5ad00b709..86c3014d95e 100644 --- a/de.metas.material/dispo/src/main/sql/postgresql/system/5461090_sys_gh523-metasfresh_add_AD_Process_MD_Candidate_Request_PP_Order.sql +++ b/de.metas.material/dispo/src/main/sql/postgresql/system/5461090_sys_gh523-metasfresh_add_AD_Process_MD_Candidate_Request_PP_Order.sql @@ -33,3 +33,8 @@ UPDATE AD_Process SET Value='MD_Candidate_Request_PP_Order',Updated=TO_TIMESTAMP INSERT INTO AD_Table_Process (AD_Client_ID,AD_Org_ID,AD_Process_ID,AD_Table_ID,Created,CreatedBy,EntityType,IsActive,Updated,UpdatedBy,WEBUI_QuickAction,WEBUI_QuickAction_Default) VALUES (0,0,540784,540808,TO_TIMESTAMP('2017-04-30 11:55:14','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.material.dispo','Y',TO_TIMESTAMP('2017-04-30 11:55:14','YYYY-MM-DD HH24:MI:SS'),100,'Y','Y') ; +-- 2017-05-03T14:59:14.905 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Process SET Classname='de.metas.material.dispo.process.MD_Candidate_Request_PP_Order',Updated=TO_TIMESTAMP('2017-05-03 14:59:14','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_ID=540784 +; + diff --git a/de.metas.material/dispo/src/main/sql/postgresql/system/5461340_sys_gh523_add_MD_event_store.sql b/de.metas.material/dispo/src/main/sql/postgresql/system/5461340_sys_gh523_add_MD_event_store.sql new file mode 100644 index 00000000000..0b7faeef906 --- /dev/null +++ b/de.metas.material/dispo/src/main/sql/postgresql/system/5461340_sys_gh523_add_MD_event_store.sql @@ -0,0 +1,171 @@ + +-- 2017-05-02T15:51:04.428 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Table (AccessLevel,ACTriggerLength,AD_Client_ID,AD_Org_ID,AD_Table_ID,CopyColumnsFromTable,Created,CreatedBy,EntityType,ImportTable,IsActive,IsAutocomplete,IsChangeLog,IsDeleteable,IsDLM,IsHighVolume,IsSecurityEnabled,IsView,LoadSeq,Name,ReplicationType,TableName,Updated,UpdatedBy) VALUES ('4',0,0,0,540814,'N',TO_TIMESTAMP('2017-05-02 15:51:04','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.material.dispo','N','Y','N','N','Y','N','N','N','N',0,'Material-Dispo-Eventstore','L','MD_EventStore',TO_TIMESTAMP('2017-05-02 15:51:04','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-02T15:51:04.431 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Table_Trl (AD_Language,AD_Table_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Table_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Table t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Table_ID=540814 AND NOT EXISTS (SELECT * FROM AD_Table_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Table_ID=t.AD_Table_ID) +; + +-- 2017-05-02T15:51:04.507 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Sequence (AD_Client_ID,AD_Org_ID,AD_Sequence_ID,Created,CreatedBy,CurrentNext,CurrentNextSys,Description,IncrementNo,IsActive,IsAudited,IsAutoSequence,IsTableID,Name,StartNewYear,StartNo,Updated,UpdatedBy) VALUES (0,0,554398,TO_TIMESTAMP('2017-05-02 15:51:04','YYYY-MM-DD HH24:MI:SS'),100,1000000,50000,'Table MD_EventStore',1,'Y','N','Y','Y','MD_EventStore','N',1000000,TO_TIMESTAMP('2017-05-02 15:51:04','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-02T15:51:16.900 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556557,102,0,19,540814,'AD_Client_ID',TO_TIMESTAMP('2017-05-02 15:51:16','YYYY-MM-DD HH24:MI:SS'),100,'Mandant für diese Installation.','de.metas.material.dispo',10,'Ein Mandant ist eine Firma oder eine juristische Person. Sie können keine Daten über Mandanten hinweg verwenden. .','Y','N','N','N','N','Y','N','N','Y','N','N','Mandant',0,TO_TIMESTAMP('2017-05-02 15:51:16','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:51:16.901 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556557 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:51:16.975 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556558,113,0,19,540814,'AD_Org_ID',TO_TIMESTAMP('2017-05-02 15:51:16','YYYY-MM-DD HH24:MI:SS'),100,'Organisatorische Einheit des Mandanten','de.metas.material.dispo',10,'Eine Organisation ist ein Bereich ihres Mandanten - z.B. Laden oder Abteilung. Sie können Daten über Organisationen hinweg gemeinsam verwenden.','Y','N','N','N','N','Y','N','N','Y','N','N','Sektion',0,TO_TIMESTAMP('2017-05-02 15:51:16','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:51:16.976 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556558 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:51:17.051 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556559,245,0,16,540814,'Created',TO_TIMESTAMP('2017-05-02 15:51:16','YYYY-MM-DD HH24:MI:SS'),100,'Datum, an dem dieser Eintrag erstellt wurde','de.metas.material.dispo',29,'Das Feld Erstellt zeigt an, zu welchem Datum dieser Eintrag erstellt wurde.','Y','N','N','N','N','Y','N','N','Y','N','N','Erstellt',0,TO_TIMESTAMP('2017-05-02 15:51:16','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:51:17.052 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556559 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:51:17.132 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Reference_Value_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556560,246,0,18,110,540814,'CreatedBy',TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100,'Nutzer, der diesen Eintrag erstellt hat','de.metas.material.dispo',10,'Das Feld Erstellt durch zeigt an, welcher Nutzer diesen Eintrag erstellt hat.','Y','N','N','N','N','Y','N','N','Y','N','N','Erstellt durch',0,TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:51:17.133 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556560 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:51:17.207 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,EntityType,FieldLength,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556561,543325,0,36,540814,'EventData',TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.material.dispo',100000,'Y','N','N','N','N','Y','N','N','N','N','N','Daten',0,TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:51:17.208 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556561 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:51:17.279 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,EntityType,FieldLength,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556562,543324,0,16,540814,'EventTime',TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.material.dispo',7,'Y','N','N','N','N','Y','N','N','N','N','N','Zeitpunkt',0,TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:51:17.280 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556562 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:51:17.356 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556563,348,0,20,540814,'IsActive',TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100,'Der Eintrag ist im System aktiv','de.metas.material.dispo',1,'Es gibt zwei Möglichkeiten, einen Datensatz nicht mehr verfügbar zu machen: einer ist, ihn zu löschen; der andere, ihn zu deaktivieren. Ein deaktivierter Eintrag ist nicht mehr für eine Auswahl verfügbar, aber verfügbar für die Verwendung in Berichten. Es gibt zwei Gründe, Datensätze zu deaktivieren und nicht zu löschen: (1) Das System braucht den Datensatz für Revisionszwecke. (2) Der Datensatz wird von anderen Datensätzen referenziert. Z.B. können Sie keinen Geschäftspartner löschen, wenn es Rechnungen für diesen Geschäftspartner gibt. Sie deaktivieren den Geschäftspartner und verhindern, dass dieser Eintrag in zukünftigen Vorgängen verwendet wird.','Y','N','N','N','N','Y','N','N','Y','N','N','Aktiv',0,TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:51:17.357 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556563 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:51:17.432 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,DefaultValue,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556564,1047,0,20,540814,'Processed',TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100,'N','Checkbox sagt aus, ob der Beleg verarbeitet wurde. ','de.metas.material.dispo',1,'Verarbeitete Belege dürfen in der Regel nich mehr geändert werden.','Y','N','N','N','N','Y','N','N','N','N','N','Verarbeitet',0,TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:51:17.433 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556564 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:51:17.508 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556565,607,0,16,540814,'Updated',TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100,'Datum, an dem dieser Eintrag aktualisiert wurde','de.metas.material.dispo',29,'Aktualisiert zeigt an, wann dieser Eintrag aktualisiert wurde.','Y','N','N','N','N','Y','N','N','Y','N','N','Aktualisiert',0,TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:51:17.509 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556565 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:51:17.580 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Reference_Value_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556566,608,0,18,110,540814,'UpdatedBy',TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100,'Nutzer, der diesen Eintrag aktualisiert hat','de.metas.material.dispo',10,'Aktualisiert durch zeigt an, welcher Nutzer diesen Eintrag aktualisiert hat.','Y','N','N','N','N','Y','N','N','Y','N','N','Aktualisiert durch',0,TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:51:17.584 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556566 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:51:17.675 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Element (AD_Client_ID,AD_Element_ID,AD_Org_ID,ColumnName,Created,CreatedBy,EntityType,IsActive,Name,PrintName,Updated,UpdatedBy) VALUES (0,543326,0,'MD_EventStore_ID',TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.material.dispo','Y','Material-Dispo-Eventstore','Material-Dispo-Eventstore',TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-02T15:51:17.678 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Element_Trl (AD_Language,AD_Element_ID, Description,Help,Name,PO_Description,PO_Help,PO_Name,PO_PrintName,PrintName, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Element_ID, t.Description,t.Help,t.Name,t.PO_Description,t.PO_Help,t.PO_Name,t.PO_PrintName,t.PrintName, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Element t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Element_ID=543326 AND NOT EXISTS (SELECT * FROM AD_Element_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Element_ID=t.AD_Element_ID) +; + +-- 2017-05-02T15:51:17.756 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,EntityType,FieldLength,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556567,543326,0,13,540814,'MD_EventStore_ID',TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.material.dispo',10,'Y','N','N','N','Y','Y','N','N','Y','N','N','Material-Dispo-Eventstore',0,TO_TIMESTAMP('2017-05-02 15:51:17','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:51:17.757 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556567 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T15:51:26.246 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Table SET IsHighVolume='Y',Updated=TO_TIMESTAMP('2017-05-02 15:51:26','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Table_ID=540814 +; + +-- 2017-05-02T15:51:47.859 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,AllowZoomTo,ColumnName,Created,CreatedBy,DDL_NoForeignKey,EntityType,FieldLength,IsActive,IsAdvancedText,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsCalculated,IsDimension,IsDLMPartitionBoundary,IsEncrypted,IsGenericZoomKeyColumn,IsGenericZoomOrigin,IsIdentifier,IsKey,IsLazyLoading,IsMandatory,IsParent,IsSelectionColumn,IsStaleable,IsSyncDatabase,IsTranslated,IsUpdateable,IsUseDocSequence,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556568,543308,0,30,540814,'N','MD_Candidate_ID',TO_TIMESTAMP('2017-05-02 15:51:47','YYYY-MM-DD HH24:MI:SS'),100,'N','de.metas.material.dispo',10,'Y','N','Y','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','Y','N','Dispositionskandidat',0,TO_TIMESTAMP('2017-05-02 15:51:47','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T15:51:47.860 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556568 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T17:03:08.247 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556571,2887,0,30,540814,'AD_Issue_ID',TO_TIMESTAMP('2017-05-02 17:03:08','YYYY-MM-DD HH24:MI:SS'),100,'Automatically created or manually entered System Issue','de.metas.material.dispo',10,'System Issues are created to speed up the resolution of any system related issues (potential bugs). If enabled, they are automatically reported to Adempiere. No data or confidential information is transferred.','Y','N','N','N','N','N','N','N','N','N','Y','System-Problem',0,TO_TIMESTAMP('2017-05-02 17:03:08','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T17:03:08.249 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556571 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-02T17:03:08.332 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,EntityType,FieldLength,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556572,543074,0,10,540814,'Event_UUID',TO_TIMESTAMP('2017-05-02 17:03:08','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.material.dispo',60,'Y','N','N','N','N','Y','N','N','N','N','N','Event UUID',0,TO_TIMESTAMP('2017-05-02 17:03:08','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-02T17:03:08.333 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556572 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + diff --git a/de.metas.material/dispo/src/main/sql/postgresql/system/5461570_sys_gh523_MD_Candidate_Prod_Detail_ddl_and_tab.sql b/de.metas.material/dispo/src/main/sql/postgresql/system/5461570_sys_gh523_MD_Candidate_Prod_Detail_ddl_and_tab.sql new file mode 100644 index 00000000000..7fc133b2ec1 --- /dev/null +++ b/de.metas.material/dispo/src/main/sql/postgresql/system/5461570_sys_gh523_MD_Candidate_Prod_Detail_ddl_and_tab.sql @@ -0,0 +1,153 @@ + +DROP TABLE IF EXISTS MD_Candidate_Prod_Detail; + +-- 2017-05-03T21:28:03.723 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +/* DDL */ CREATE TABLE public.MD_Candidate_Prod_Detail (AD_Client_ID NUMERIC(10) NOT NULL, AD_Org_ID NUMERIC(10) NOT NULL, C_UOM_ID NUMERIC(10), Created TIMESTAMP WITH TIME ZONE NOT NULL, CreatedBy NUMERIC(10) NOT NULL, Description VARCHAR(2000), IsActive CHAR(1) CHECK (IsActive IN ('Y','N')) NOT NULL, MD_Candidate_ID NUMERIC(10), MD_Candidate_Prod_Detail_ID NUMERIC(10) NOT NULL, PP_Order_BOMLine_ID NUMERIC(10), PP_Order_DocStatus VARCHAR(2), PP_Order_ID NUMERIC(10), PP_Plant_ID NUMERIC(10), PP_Product_BOMLine_ID NUMERIC(10), PP_Product_Planning_ID NUMERIC(10), Updated TIMESTAMP WITH TIME ZONE NOT NULL, UpdatedBy NUMERIC(10) NOT NULL, CONSTRAINT CUOM_MDCandidateProdDetail FOREIGN KEY (C_UOM_ID) REFERENCES public.C_UOM DEFERRABLE INITIALLY DEFERRED, CONSTRAINT MDCandidate_MDCandidateProdDet FOREIGN KEY (MD_Candidate_ID) REFERENCES public.MD_Candidate DEFERRABLE INITIALLY DEFERRED, CONSTRAINT MD_Candidate_Prod_Detail_Key PRIMARY KEY (MD_Candidate_Prod_Detail_ID), CONSTRAINT PPOrderBOMLine_MDCandidateProd FOREIGN KEY (PP_Order_BOMLine_ID) REFERENCES public.PP_Order_BOMLine DEFERRABLE INITIALLY DEFERRED, CONSTRAINT PPOrder_MDCandidateProdDetail FOREIGN KEY (PP_Order_ID) REFERENCES public.PP_Order DEFERRABLE INITIALLY DEFERRED, CONSTRAINT PPPlant_MDCandidateProdDetail FOREIGN KEY (PP_Plant_ID) REFERENCES public.S_Resource DEFERRABLE INITIALLY DEFERRED, CONSTRAINT PPProductBOMLine_MDCandidatePr FOREIGN KEY (PP_Product_BOMLine_ID) REFERENCES public.PP_Product_BOMLine DEFERRABLE INITIALLY DEFERRED, CONSTRAINT PPProductPlanning_MDCandidateP FOREIGN KEY (PP_Product_Planning_ID) REFERENCES public.PP_Product_Planning DEFERRABLE INITIALLY DEFERRED) +; + +-- 2017-05-03T21:34:08.276 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Tab (AD_Client_ID,AD_Column_ID,AD_Org_ID,AD_Tab_ID,AD_Table_ID,AD_Window_ID,Created,CreatedBy,DisplayLogic,EntityType,HasTree,ImportFields,IsActive,IsAdvancedTab,IsCheckParentsChanged,IsGenericZoomTarget,IsGridModeOnly,IsInfoTab,IsInsertRecord,IsQueryOnLoad,IsReadOnly,IsRefreshAllOnActivate,IsSearchActive,IsSearchCollapsed,IsSingleRow,IsSortTab,IsTranslationTab,MaxQueryRecords,Name,Processing,SeqNo,TabLevel,Updated,UpdatedBy) VALUES (0,556531,0,540811,540810,540334,TO_TIMESTAMP('2017-05-03 21:34:08','YYYY-MM-DD HH24:MI:SS'),100,'@MD_Candidate_SubType@=PRODUCTION','de.metas.material.dispo','N','N','Y','N','Y','N','N','N','N','Y','Y','N','N','Y','N','N','N',0,'Produktionsdetail','N',20,0,TO_TIMESTAMP('2017-05-03 21:34:08','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-03T21:34:08.283 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Tab_Trl (AD_Language,AD_Tab_ID, CommitWarning,Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Tab_ID, t.CommitWarning,t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Tab t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Tab_ID=540811 AND NOT EXISTS (SELECT * FROM AD_Tab_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Tab_ID=t.AD_Tab_ID) +; + +-- 2017-05-03T21:34:12.266 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,Description,DisplayLength,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556516,558292,0,540811,TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100,'Mandant für diese Installation.',10,'de.metas.material.dispo','Ein Mandant ist eine Firma oder eine juristische Person. Sie können keine Daten über Mandanten hinweg verwenden. .','Y','Y','Y','N','N','N','N','N','Mandant',TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-03T21:34:12.271 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558292 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-03T21:34:12.359 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,Description,DisplayLength,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556517,558293,0,540811,TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100,'Organisatorische Einheit des Mandanten',10,'de.metas.material.dispo','Eine Organisation ist ein Bereich ihres Mandanten - z.B. Laden oder Abteilung. Sie können Daten über Organisationen hinweg gemeinsam verwenden.','Y','Y','Y','N','N','N','N','N','Sektion',TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-03T21:34:12.360 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558293 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-03T21:34:12.430 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,Description,DisplayLength,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556520,558294,0,540811,TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100,'Der Eintrag ist im System aktiv',1,'de.metas.material.dispo','Es gibt zwei Möglichkeiten, einen Datensatz nicht mehr verfügbar zu machen: einer ist, ihn zu löschen; der andere, ihn zu deaktivieren. Ein deaktivierter Eintrag ist nicht mehr für eine Auswahl verfügbar, aber verfügbar für die Verwendung in Berichten. Es gibt zwei Gründe, Datensätze zu deaktivieren und nicht zu löschen: (1) Das System braucht den Datensatz für Revisionszwecke. (2) Der Datensatz wird von anderen Datensätzen referenziert. Z.B. können Sie keinen Geschäftspartner löschen, wenn es Rechnungen für diesen Geschäftspartner gibt. Sie deaktivieren den Geschäftspartner und verhindern, dass dieser Eintrag in zukünftigen Vorgängen verwendet wird.','Y','Y','Y','N','N','N','N','N','Aktiv',TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-03T21:34:12.431 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558294 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-03T21:34:12.503 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,DisplayLength,EntityType,IsActive,IsCentrallyMaintained,IsDisplayed,IsDisplayedGrid,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556523,558295,0,540811,TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100,10,'de.metas.material.dispo','Y','Y','N','N','N','N','N','N','N','Dispo-Produktionsdetail',TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-03T21:34:12.504 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558295 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-03T21:34:12.574 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,Description,DisplayLength,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556524,558296,0,540811,TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100,'BOM Line',10,'de.metas.material.dispo','The BOM Line is a unique identifier for a BOM line in an BOM.','Y','Y','Y','N','N','N','N','N','BOM Line',TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-03T21:34:12.575 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558296 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-03T21:34:12.645 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,DisplayLength,EntityType,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556525,558297,0,540811,TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100,10,'de.metas.material.dispo','Y','Y','Y','N','N','N','N','N','Product Planning',TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-03T21:34:12.647 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558297 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-03T21:34:12.722 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,DisplayLength,EntityType,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556526,558298,0,540811,TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100,10,'de.metas.material.dispo','Y','Y','Y','N','N','N','N','N','Produktionsstätte',TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-03T21:34:12.723 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558298 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-03T21:34:12.804 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,DisplayLength,EntityType,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556530,558299,0,540811,TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100,2000,'de.metas.material.dispo','Y','Y','Y','N','N','N','N','N','Beschreibung',TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-03T21:34:12.805 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558299 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-03T21:34:12.878 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,DisplayLength,EntityType,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556531,558300,0,540811,TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100,10,'de.metas.material.dispo','Y','Y','Y','N','N','N','N','N','Dispositionskandidat',TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-03T21:34:12.879 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558300 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-03T21:34:12.953 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,Description,DisplayLength,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556532,558301,0,540811,TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100,'Maßeinheit',10,'de.metas.material.dispo','Eine eindeutige (nicht monetäre) Maßeinheit','Y','Y','Y','N','N','N','N','N','Maßeinheit',TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-03T21:34:12.954 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558301 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-03T21:34:13.027 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,DisplayLength,EntityType,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556534,558302,0,540811,TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100,10,'de.metas.material.dispo','Y','Y','Y','N','N','N','N','N','Produktionsauftrag',TO_TIMESTAMP('2017-05-03 21:34:12','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-03T21:34:13.028 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558302 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-03T21:34:13.099 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,DisplayLength,EntityType,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556535,558303,0,540811,TO_TIMESTAMP('2017-05-03 21:34:13','YYYY-MM-DD HH24:MI:SS'),100,10,'de.metas.material.dispo','Y','Y','Y','N','N','N','N','N','Manufacturing Order BOM Line',TO_TIMESTAMP('2017-05-03 21:34:13','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-03T21:34:13.100 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558303 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-03T21:34:13.172 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,DisplayLength,EntityType,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556536,558304,0,540811,TO_TIMESTAMP('2017-05-03 21:34:13','YYYY-MM-DD HH24:MI:SS'),100,2,'de.metas.material.dispo','Y','Y','Y','N','N','N','N','N','Belegstatus',TO_TIMESTAMP('2017-05-03 21:34:13','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-03T21:34:13.173 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558304 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-03T21:35:43.650 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Tab SET TabLevel=1,Updated=TO_TIMESTAMP('2017-05-03 21:35:43','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Tab_ID=540811 +; + diff --git a/de.metas.material/dispo/src/main/sql/postgresql/system/5461630_sys_gh523_table_MD_Candidate_Demand_Detail.sql b/de.metas.material/dispo/src/main/sql/postgresql/system/5461630_sys_gh523_table_MD_Candidate_Demand_Detail.sql new file mode 100644 index 00000000000..4668903b759 --- /dev/null +++ b/de.metas.material/dispo/src/main/sql/postgresql/system/5461630_sys_gh523_table_MD_Candidate_Demand_Detail.sql @@ -0,0 +1,205 @@ + + +-- 2017-05-04T10:08:29.728 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Table (AccessLevel,ACTriggerLength,AD_Client_ID,AD_Org_ID,AD_Table_ID,AD_Window_ID,CopyColumnsFromTable,Created,CreatedBy,EntityType,ImportTable,IsActive,IsAutocomplete,IsChangeLog,IsDeleteable,IsDLM,IsHighVolume,IsSecurityEnabled,IsView,LoadSeq,Name,ReplicationType,TableName,Updated,UpdatedBy) VALUES ('1',0,0,0,540815,540334,'N',TO_TIMESTAMP('2017-05-04 10:08:29','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.material.dispo','N','Y','N','N','Y','N','N','N','N',0,'Dispo-Bedarfsdetail','L','MD_Candidate_Demand_Detail',TO_TIMESTAMP('2017-05-04 10:08:29','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-04T10:08:29.734 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Table_Trl (AD_Language,AD_Table_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Table_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Table t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Table_ID=540815 AND NOT EXISTS (SELECT * FROM AD_Table_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Table_ID=t.AD_Table_ID) +; + +-- 2017-05-04T10:08:29.936 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Sequence (AD_Client_ID,AD_Org_ID,AD_Sequence_ID,Created,CreatedBy,CurrentNext,CurrentNextSys,Description,IncrementNo,IsActive,IsAudited,IsAutoSequence,IsTableID,Name,StartNewYear,StartNo,Updated,UpdatedBy) VALUES (0,0,554399,TO_TIMESTAMP('2017-05-04 10:08:29','YYYY-MM-DD HH24:MI:SS'),100,1000000,50000,'Table MD_Candidate_Demand_Detail',1,'Y','N','Y','Y','MD_Candidate_Demand_Detail','N',1000000,TO_TIMESTAMP('2017-05-04 10:08:29','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-04T10:09:23.682 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Table SET Description='Each record contains detailed infos about one MD_Candidates with subtype=Shipment', Name='Dispo-Warenausgangsdetail', TableName='MD_Candidate_Shipment_Detail',Updated=TO_TIMESTAMP('2017-05-04 10:09:23','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Table_ID=540815 +; + +-- 2017-05-04T10:09:23.687 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Table_Trl SET IsTranslated='N' WHERE AD_Table_ID=540815 +; + +-- 2017-05-04T10:09:23.699 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Sequence SET Name='MD_Candidate_Shipment_Detail',Updated=TO_TIMESTAMP('2017-05-04 10:09:23','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Sequence_ID=554399 +; + +-- 2017-05-04T10:09:30.985 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556573,102,0,19,540815,'AD_Client_ID',TO_TIMESTAMP('2017-05-04 10:09:30','YYYY-MM-DD HH24:MI:SS'),100,'Mandant für diese Installation.','de.metas.material.dispo',10,'Ein Mandant ist eine Firma oder eine juristische Person. Sie können keine Daten über Mandanten hinweg verwenden. .','Y','N','N','N','N','Y','N','N','Y','N','N','Mandant',0,TO_TIMESTAMP('2017-05-04 10:09:30','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-04T10:09:30.991 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556573 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-04T10:09:31.086 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556574,113,0,19,540815,'AD_Org_ID',TO_TIMESTAMP('2017-05-04 10:09:31','YYYY-MM-DD HH24:MI:SS'),100,'Organisatorische Einheit des Mandanten','de.metas.material.dispo',10,'Eine Organisation ist ein Bereich ihres Mandanten - z.B. Laden oder Abteilung. Sie können Daten über Organisationen hinweg gemeinsam verwenden.','Y','N','N','N','N','Y','N','N','Y','N','N','Sektion',0,TO_TIMESTAMP('2017-05-04 10:09:31','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-04T10:09:31.087 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556574 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-04T10:09:31.161 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556575,245,0,16,540815,'Created',TO_TIMESTAMP('2017-05-04 10:09:31','YYYY-MM-DD HH24:MI:SS'),100,'Datum, an dem dieser Eintrag erstellt wurde','de.metas.material.dispo',29,'Das Feld Erstellt zeigt an, zu welchem Datum dieser Eintrag erstellt wurde.','Y','N','N','N','N','Y','N','N','Y','N','N','Erstellt',0,TO_TIMESTAMP('2017-05-04 10:09:31','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-04T10:09:31.162 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556575 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-04T10:09:31.234 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Reference_Value_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556576,246,0,18,110,540815,'CreatedBy',TO_TIMESTAMP('2017-05-04 10:09:31','YYYY-MM-DD HH24:MI:SS'),100,'Nutzer, der diesen Eintrag erstellt hat','de.metas.material.dispo',10,'Das Feld Erstellt durch zeigt an, welcher Nutzer diesen Eintrag erstellt hat.','Y','N','N','N','N','Y','N','N','Y','N','N','Erstellt durch',0,TO_TIMESTAMP('2017-05-04 10:09:31','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-04T10:09:31.235 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556576 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-04T10:09:31.315 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556577,348,0,20,540815,'IsActive',TO_TIMESTAMP('2017-05-04 10:09:31','YYYY-MM-DD HH24:MI:SS'),100,'Der Eintrag ist im System aktiv','de.metas.material.dispo',1,'Es gibt zwei Möglichkeiten, einen Datensatz nicht mehr verfügbar zu machen: einer ist, ihn zu löschen; der andere, ihn zu deaktivieren. Ein deaktivierter Eintrag ist nicht mehr für eine Auswahl verfügbar, aber verfügbar für die Verwendung in Berichten. Es gibt zwei Gründe, Datensätze zu deaktivieren und nicht zu löschen: (1) Das System braucht den Datensatz für Revisionszwecke. (2) Der Datensatz wird von anderen Datensätzen referenziert. Z.B. können Sie keinen Geschäftspartner löschen, wenn es Rechnungen für diesen Geschäftspartner gibt. Sie deaktivieren den Geschäftspartner und verhindern, dass dieser Eintrag in zukünftigen Vorgängen verwendet wird.','Y','N','N','N','N','Y','N','N','Y','N','Y','Aktiv',0,TO_TIMESTAMP('2017-05-04 10:09:31','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-04T10:09:31.316 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556577 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-04T10:09:31.395 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556578,607,0,16,540815,'Updated',TO_TIMESTAMP('2017-05-04 10:09:31','YYYY-MM-DD HH24:MI:SS'),100,'Datum, an dem dieser Eintrag aktualisiert wurde','de.metas.material.dispo',29,'Aktualisiert zeigt an, wann dieser Eintrag aktualisiert wurde.','Y','N','N','N','N','Y','N','N','Y','N','N','Aktualisiert',0,TO_TIMESTAMP('2017-05-04 10:09:31','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-04T10:09:31.396 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556578 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-04T10:09:31.471 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Reference_Value_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556579,608,0,18,110,540815,'UpdatedBy',TO_TIMESTAMP('2017-05-04 10:09:31','YYYY-MM-DD HH24:MI:SS'),100,'Nutzer, der diesen Eintrag aktualisiert hat','de.metas.material.dispo',10,'Aktualisiert durch zeigt an, welcher Nutzer diesen Eintrag aktualisiert hat.','Y','N','N','N','N','Y','N','N','Y','N','N','Aktualisiert durch',0,TO_TIMESTAMP('2017-05-04 10:09:31','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-04T10:09:31.472 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556579 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-04T10:09:31.545 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Element (AD_Client_ID,AD_Element_ID,AD_Org_ID,ColumnName,Created,CreatedBy,EntityType,IsActive,Name,PrintName,Updated,UpdatedBy) VALUES (0,543327,0,'MD_Candidate_Shipment_Detail_ID',TO_TIMESTAMP('2017-05-04 10:09:31','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.material.dispo','Y','Dispo-Warenausgangsdetail','Dispo-Warenausgangsdetail',TO_TIMESTAMP('2017-05-04 10:09:31','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-04T10:09:31.551 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Element_Trl (AD_Language,AD_Element_ID, Description,Help,Name,PO_Description,PO_Help,PO_Name,PO_PrintName,PrintName, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Element_ID, t.Description,t.Help,t.Name,t.PO_Description,t.PO_Help,t.PO_Name,t.PO_PrintName,t.PrintName, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Element t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Element_ID=543327 AND NOT EXISTS (SELECT * FROM AD_Element_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Element_ID=t.AD_Element_ID) +; + +-- 2017-05-04T10:09:31.639 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,EntityType,FieldLength,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556580,543327,0,13,540815,'MD_Candidate_Shipment_Detail_ID',TO_TIMESTAMP('2017-05-04 10:09:31','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.material.dispo',10,'Y','N','N','N','Y','Y','N','N','Y','N','N','Dispo-Warenausgangsdetail',0,TO_TIMESTAMP('2017-05-04 10:09:31','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-04T10:09:31.640 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556580 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-04T10:09:51.427 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,AllowZoomTo,ColumnName,Created,CreatedBy,DDL_NoForeignKey,EntityType,FieldLength,IsActive,IsAdvancedText,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsCalculated,IsDimension,IsDLMPartitionBoundary,IsEncrypted,IsGenericZoomKeyColumn,IsGenericZoomOrigin,IsIdentifier,IsKey,IsLazyLoading,IsMandatory,IsParent,IsSelectionColumn,IsStaleable,IsSyncDatabase,IsTranslated,IsUpdateable,IsUseDocSequence,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556581,543308,0,30,540815,'N','MD_Candidate_ID',TO_TIMESTAMP('2017-05-04 10:09:51','YYYY-MM-DD HH24:MI:SS'),100,'N','de.metas.material.dispo',10,'Y','N','Y','N','N','N','N','N','N','N','N','N','N','N','Y','Y','N','N','N','N','N','N','Dispositionskandidat',0,TO_TIMESTAMP('2017-05-04 10:09:51','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-04T10:09:51.429 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556581 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-04T10:10:12.460 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,AllowZoomTo,ColumnName,Created,CreatedBy,DDL_NoForeignKey,Description,EntityType,FieldLength,Help,IsActive,IsAdvancedText,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsCalculated,IsDimension,IsDLMPartitionBoundary,IsEncrypted,IsGenericZoomKeyColumn,IsGenericZoomOrigin,IsIdentifier,IsKey,IsLazyLoading,IsMandatory,IsParent,IsSelectionColumn,IsStaleable,IsSyncDatabase,IsTranslated,IsUpdateable,IsUseDocSequence,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,556582,561,0,30,540815,'N','C_OrderLine_ID',TO_TIMESTAMP('2017-05-04 10:10:12','YYYY-MM-DD HH24:MI:SS'),100,'N','Auftragsposition','de.metas.material.dispo',10,'"Auftragsposition" bezeichnet eine einzelne Position in einem Auftrag.','Y','N','Y','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','Y','N','Auftragsposition',0,TO_TIMESTAMP('2017-05-04 10:10:12','YYYY-MM-DD HH24:MI:SS'),100,0) +; + +-- 2017-05-04T10:10:12.462 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=556582 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID) +; + +-- 2017-05-04T10:11:44.880 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Element SET ColumnName='MD_Candidate_Demand_Detail_ID', Name='Dispo-Bedarfsdetail', PrintName='Dispo-Bedarfsdetail',Updated=TO_TIMESTAMP('2017-05-04 10:11:44','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Element_ID=543327 +; + +-- 2017-05-04T10:11:44.882 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Element_Trl SET IsTranslated='N' WHERE AD_Element_ID=543327 +; + +-- 2017-05-04T10:11:44.885 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Column SET ColumnName='MD_Candidate_Demand_Detail_ID', Name='Dispo-Bedarfsdetail', Description=NULL, Help=NULL WHERE AD_Element_ID=543327 +; + +-- 2017-05-04T10:11:44.905 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Process_Para SET ColumnName='MD_Candidate_Demand_Detail_ID', Name='Dispo-Bedarfsdetail', Description=NULL, Help=NULL, AD_Element_ID=543327 WHERE UPPER(ColumnName)='MD_CANDIDATE_DEMAND_DETAIL_ID' AND IsCentrallyMaintained='Y' AND AD_Element_ID IS NULL +; + +-- 2017-05-04T10:11:44.909 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Process_Para SET ColumnName='MD_Candidate_Demand_Detail_ID', Name='Dispo-Bedarfsdetail', Description=NULL, Help=NULL WHERE AD_Element_ID=543327 AND IsCentrallyMaintained='Y' +; + +-- 2017-05-04T10:11:44.910 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Field SET Name='Dispo-Bedarfsdetail', Description=NULL, Help=NULL WHERE AD_Column_ID IN (SELECT AD_Column_ID FROM AD_Column WHERE AD_Element_ID=543327) AND IsCentrallyMaintained='Y' +; + +-- 2017-05-04T10:11:44.926 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_PrintFormatItem pi SET PrintName='Dispo-Bedarfsdetail', Name='Dispo-Bedarfsdetail' WHERE IsCentrallyMaintained='Y' AND EXISTS (SELECT * FROM AD_Column c WHERE c.AD_Column_ID=pi.AD_Column_ID AND c.AD_Element_ID=543327) +; + +-- 2017-05-04T10:12:20.061 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Table SET Description='', Name='Dispo-Bedarfsdetail',Updated=TO_TIMESTAMP('2017-05-04 10:12:20','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Table_ID=540815 +; + +-- 2017-05-04T10:12:20.063 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Table_Trl SET IsTranslated='N' WHERE AD_Table_ID=540815 +; + +-- 2017-05-04T10:12:30.084 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Table SET TableName='MD_Candidate_Demand_Detail',Updated=TO_TIMESTAMP('2017-05-04 10:12:30','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Table_ID=540815 +; + +-- 2017-05-04T10:12:30.088 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Sequence SET Name='MD_Candidate_Demand_Detail',Updated=TO_TIMESTAMP('2017-05-04 10:12:30','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Sequence_ID=554399 +; + + +DROP TABLE IF EXISTS public.MD_Candidate_Demand_Detail; + +-- 2017-05-04T13:38:24.029 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +/* DDL */ CREATE TABLE public.MD_Candidate_Demand_Detail (AD_Client_ID NUMERIC(10) NOT NULL, AD_Org_ID NUMERIC(10) NOT NULL, C_OrderLine_ID NUMERIC(10), Created TIMESTAMP WITH TIME ZONE NOT NULL, CreatedBy NUMERIC(10) NOT NULL, IsActive CHAR(1) CHECK (IsActive IN ('Y','N')) NOT NULL, MD_Candidate_Demand_Detail_ID NUMERIC(10) NOT NULL, MD_Candidate_ID NUMERIC(10) NOT NULL, Updated TIMESTAMP WITH TIME ZONE NOT NULL, UpdatedBy NUMERIC(10) NOT NULL, CONSTRAINT COrderLine_MDCandidateDemandDe FOREIGN KEY (C_OrderLine_ID) REFERENCES public.C_OrderLine DEFERRABLE INITIALLY DEFERRED, CONSTRAINT MD_Candidate_Demand_Detail_Key PRIMARY KEY (MD_Candidate_Demand_Detail_ID), CONSTRAINT MDCandidate_MDCandidateDemandD FOREIGN KEY (MD_Candidate_ID) REFERENCES public.MD_Candidate DEFERRABLE INITIALLY DEFERRED) +; + diff --git a/de.metas.material/dispo/src/main/sql/postgresql/system/5461760_sys_gh523-metasfresh_tab_MD_Candidate_Demand_Detail.sql b/de.metas.material/dispo/src/main/sql/postgresql/system/5461760_sys_gh523-metasfresh_tab_MD_Candidate_Demand_Detail.sql new file mode 100644 index 00000000000..13ba9a10659 --- /dev/null +++ b/de.metas.material/dispo/src/main/sql/postgresql/system/5461760_sys_gh523-metasfresh_tab_MD_Candidate_Demand_Detail.sql @@ -0,0 +1,80 @@ +-- 2017-05-04T16:13:58.463 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Tab (AD_Client_ID,AD_Column_ID,AD_Org_ID,AD_Tab_ID,AD_Table_ID,AD_Window_ID,Created,CreatedBy,EntityType,HasTree,ImportFields,IsActive,IsAdvancedTab,IsCheckParentsChanged,IsGenericZoomTarget,IsGridModeOnly,IsInfoTab,IsInsertRecord,IsQueryOnLoad,IsReadOnly,IsRefreshAllOnActivate,IsSearchActive,IsSearchCollapsed,IsSingleRow,IsSortTab,IsTranslationTab,MaxQueryRecords,Name,Processing,SeqNo,TabLevel,Updated,UpdatedBy) VALUES (0,556581,0,540814,540815,540334,TO_TIMESTAMP('2017-05-04 16:13:58','YYYY-MM-DD HH24:MI:SS'),100,'U','N','N','Y','N','Y','N','N','N','N','Y','Y','N','Y','Y','N','N','N',0,'Bedarfsdetail','N',30,1,TO_TIMESTAMP('2017-05-04 16:13:58','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-04T16:13:58.474 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Tab_Trl (AD_Language,AD_Tab_ID, CommitWarning,Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Tab_ID, t.CommitWarning,t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Tab t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Tab_ID=540814 AND NOT EXISTS (SELECT * FROM AD_Tab_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Tab_ID=t.AD_Tab_ID) +; + +-- 2017-05-04T16:14:07.567 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Tab SET EntityType='de.metas.material.dispo',Updated=TO_TIMESTAMP('2017-05-04 16:14:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Tab_ID=540814 +; + +-- 2017-05-04T16:14:10.661 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,Description,DisplayLength,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556573,558361,0,540814,TO_TIMESTAMP('2017-05-04 16:14:10','YYYY-MM-DD HH24:MI:SS'),100,'Mandant für diese Installation.',10,'de.metas.material.dispo','Ein Mandant ist eine Firma oder eine juristische Person. Sie können keine Daten über Mandanten hinweg verwenden. .','Y','Y','Y','N','N','N','N','N','Mandant',TO_TIMESTAMP('2017-05-04 16:14:10','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-04T16:14:10.665 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558361 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-04T16:14:10.742 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,Description,DisplayLength,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556574,558362,0,540814,TO_TIMESTAMP('2017-05-04 16:14:10','YYYY-MM-DD HH24:MI:SS'),100,'Organisatorische Einheit des Mandanten',10,'de.metas.material.dispo','Eine Organisation ist ein Bereich ihres Mandanten - z.B. Laden oder Abteilung. Sie können Daten über Organisationen hinweg gemeinsam verwenden.','Y','Y','Y','N','N','N','N','N','Sektion',TO_TIMESTAMP('2017-05-04 16:14:10','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-04T16:14:10.743 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558362 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-04T16:14:10.819 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,Description,DisplayLength,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556577,558363,0,540814,TO_TIMESTAMP('2017-05-04 16:14:10','YYYY-MM-DD HH24:MI:SS'),100,'Der Eintrag ist im System aktiv',1,'de.metas.material.dispo','Es gibt zwei Möglichkeiten, einen Datensatz nicht mehr verfügbar zu machen: einer ist, ihn zu löschen; der andere, ihn zu deaktivieren. Ein deaktivierter Eintrag ist nicht mehr für eine Auswahl verfügbar, aber verfügbar für die Verwendung in Berichten. Es gibt zwei Gründe, Datensätze zu deaktivieren und nicht zu löschen: (1) Das System braucht den Datensatz für Revisionszwecke. (2) Der Datensatz wird von anderen Datensätzen referenziert. Z.B. können Sie keinen Geschäftspartner löschen, wenn es Rechnungen für diesen Geschäftspartner gibt. Sie deaktivieren den Geschäftspartner und verhindern, dass dieser Eintrag in zukünftigen Vorgängen verwendet wird.','Y','Y','Y','N','N','N','N','N','Aktiv',TO_TIMESTAMP('2017-05-04 16:14:10','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-04T16:14:10.820 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558363 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-04T16:14:10.896 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,DisplayLength,EntityType,IsActive,IsCentrallyMaintained,IsDisplayed,IsDisplayedGrid,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556580,558364,0,540814,TO_TIMESTAMP('2017-05-04 16:14:10','YYYY-MM-DD HH24:MI:SS'),100,10,'de.metas.material.dispo','Y','Y','N','N','N','N','N','N','N','Dispo-Bedarfsdetail',TO_TIMESTAMP('2017-05-04 16:14:10','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-04T16:14:10.897 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558364 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-04T16:14:10.970 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,DisplayLength,EntityType,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556581,558365,0,540814,TO_TIMESTAMP('2017-05-04 16:14:10','YYYY-MM-DD HH24:MI:SS'),100,10,'de.metas.material.dispo','Y','Y','Y','N','N','N','N','N','Dispositionskandidat',TO_TIMESTAMP('2017-05-04 16:14:10','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-04T16:14:10.971 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558365 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-04T16:14:11.044 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,Description,DisplayLength,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,Updated,UpdatedBy) VALUES (0,556582,558366,0,540814,TO_TIMESTAMP('2017-05-04 16:14:10','YYYY-MM-DD HH24:MI:SS'),100,'Auftragsposition',10,'de.metas.material.dispo','"Auftragsposition" bezeichnet eine einzelne Position in einem Auftrag.','Y','Y','Y','N','N','N','N','N','Auftragsposition',TO_TIMESTAMP('2017-05-04 16:14:10','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-04T16:14:11.045 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=558366 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID) +; + +-- 2017-05-04T16:24:24.853 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Tab SET DisplayLogic='@MD_Candidate_Type@!=STOCK',Updated=TO_TIMESTAMP('2017-05-04 16:24:24','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Tab_ID=540814 +; + diff --git a/de.metas.material/dispo/src/main/sql/postgresql/system/5461780_sys_gh523-metasfresh_AD_RelationType.sql b/de.metas.material/dispo/src/main/sql/postgresql/system/5461780_sys_gh523-metasfresh_AD_RelationType.sql new file mode 100644 index 00000000000..3f4a43efab5 --- /dev/null +++ b/de.metas.material/dispo/src/main/sql/postgresql/system/5461780_sys_gh523-metasfresh_AD_RelationType.sql @@ -0,0 +1,105 @@ + +-- +-- C_Order => MD_Candidate +-- + +-- 2017-05-04T16:28:40.500 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Reference (AD_Client_ID,AD_Org_ID,AD_Reference_ID,Created,CreatedBy,EntityType,IsActive,IsOrderByValue,Name,Updated,UpdatedBy,ValidationType) VALUES (0,0,540720,TO_TIMESTAMP('2017-05-04 16:28:40','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.material.dispo','Y','N','MD_Candidate_Target_For_C_Order',TO_TIMESTAMP('2017-05-04 16:28:40','YYYY-MM-DD HH24:MI:SS'),100,'T') +; + +-- 2017-05-04T16:28:40.508 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Reference_Trl (AD_Language,AD_Reference_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Reference_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Reference t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Reference_ID=540720 AND NOT EXISTS (SELECT * FROM AD_Reference_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Reference_ID=t.AD_Reference_ID) +; + +-- 2017-05-04T16:29:27.323 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Ref_Table (AD_Client_ID,AD_Key,AD_Org_ID,AD_Reference_ID,AD_Table_ID,AD_Window_ID,Created,CreatedBy,EntityType,IsActive,IsValueDisplayed,Updated,UpdatedBy,WhereClause) VALUES (0,556473,0,540720,540808,540334,TO_TIMESTAMP('2017-05-04 16:29:27','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.material.dispo','Y','N',TO_TIMESTAMP('2017-05-04 16:29:27','YYYY-MM-DD HH24:MI:SS'),100,'exists +( + select 1 + from MD_Candidate_Demand_Detail cdd + join C_OrderLine ol on cdd.C_OrderLine_ID = ol.C_OrderLine_ID + where + ol.C_Order_ID = @C_Order_ID/-1@ AND MD_Candidate.MD_Candidate_ID = cdd.MD_Candidate_ID +)') +; + +-- 2017-05-04T16:30:03.029 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_RelationType (AD_Client_ID,AD_Org_ID,AD_Reference_Source_ID,AD_Reference_Target_ID,AD_RelationType_ID,Created,CreatedBy,EntityType,IsActive,IsDirected,Name,Updated,UpdatedBy) VALUES (0,0,540666,540720,540178,TO_TIMESTAMP('2017-05-04 16:30:02','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.material.dispo','Y','Y','C_Order -> MD_Candidate',TO_TIMESTAMP('2017-05-04 16:30:02','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-05T14:07:06.926 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Reference (AD_Client_ID,AD_Org_ID,AD_Reference_ID,Created,CreatedBy,EntityType,IsActive,IsOrderByValue,Name,Updated,UpdatedBy,ValidationType) VALUES (0,0,540721,TO_TIMESTAMP('2017-05-05 14:07:06','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.material.dispo','Y','N','MD_Candidate_Production_Target_For_C_Order',TO_TIMESTAMP('2017-05-05 14:07:06','YYYY-MM-DD HH24:MI:SS'),100,'T') +; + +-- 2017-05-05T14:07:06.942 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Reference_Trl (AD_Language,AD_Reference_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Reference_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Reference t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Reference_ID=540721 AND NOT EXISTS (SELECT * FROM AD_Reference_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Reference_ID=t.AD_Reference_ID) +; + +-- 2017-05-05T14:24:48.110 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Ref_Table (AD_Client_ID,AD_Key,AD_Org_ID,AD_Reference_ID,AD_Table_ID,AD_Window_ID,Created,CreatedBy,EntityType,IsActive,IsValueDisplayed,Updated,UpdatedBy,WhereClause) VALUES (0,556473,0,540721,540808,540334,TO_TIMESTAMP('2017-05-05 14:24:48','YYYY-MM-DD HH24:MI:SS'),100,'U','Y','N',TO_TIMESTAMP('2017-05-05 14:24:48','YYYY-MM-DD HH24:MI:SS'),100,'MD_Candidate_SubType=''PRODUCTION'' +AND exists ( + select 1 from MD_Candidate_Demand_Detail cdd + join C_OrderLine ol on cdd.C_OrderLine_ID = ol.C_OrderLine_ID + where + ol.C_Order_ID = @C_Order_ID/-1@ AND MD_Candidate.MD_Candidate_ID = cdd.MD_Candidate_ID +)') +; + +-- 2017-05-05T14:24:59.177 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Reference SET Name='MD_Candidate_PRODUCTION_Target_For_C_Order',Updated=TO_TIMESTAMP('2017-05-05 14:24:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Reference_ID=540721 +; + +-- 2017-05-05T14:24:59.179 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Reference_Trl SET IsTranslated='N' WHERE AD_Reference_ID=540721 +; + +-- 2017-05-05T14:42:02.311 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_RelationType (AD_Client_ID,AD_Org_ID,AD_Reference_Source_ID,AD_Reference_Target_ID,AD_RelationType_ID,Created,CreatedBy,EntityType,IsActive,IsDirected,Name,Updated,UpdatedBy) VALUES (0,0,540666,540721,540179,TO_TIMESTAMP('2017-05-05 14:42:02','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.swat','Y','Y','C_Order -> MD_Candidate_Just_Production',TO_TIMESTAMP('2017-05-05 14:42:02','YYYY-MM-DD HH24:MI:SS'),100) +; + +-- 2017-05-05T14:45:08.236 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Ref_List (AD_Client_ID,AD_Org_ID,AD_Ref_List_ID,AD_Reference_ID,Created,CreatedBy,EntityType,IsActive,Name,Updated,UpdatedBy,Value,ValueName) VALUES (0,0,541272,53331,TO_TIMESTAMP('2017-05-05 14:45:08','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.material.dispo','Y','Materialdispo (Produktion)',TO_TIMESTAMP('2017-05-05 14:45:08','YYYY-MM-DD HH24:MI:SS'),100,'MD_Candidate_PRODUCTION','MD_Candidate_PRODUCTION') +; + +-- 2017-05-05T14:45:08.241 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Ref_List_Trl (AD_Language,AD_Ref_List_ID, Description,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Ref_List_ID, t.Description,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Ref_List t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Ref_List_ID=541272 AND NOT EXISTS (SELECT * FROM AD_Ref_List_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Ref_List_ID=t.AD_Ref_List_ID) +; + +-- 2017-05-05T14:45:45.840 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_RelationType SET EntityType='de.metas.material.dispo', Role_Target='MD_Candidate_PRODUCTION',Updated=TO_TIMESTAMP('2017-05-05 14:45:45','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_RelationType_ID=540179 +; + +-- 2017-05-05T14:45:51.936 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_RelationType SET IsActive='N',Updated=TO_TIMESTAMP('2017-05-05 14:45:51','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_RelationType_ID=540178 +; + +-- 2017-05-05T14:45:59.656 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_RelationType SET IsActive='Y',Updated=TO_TIMESTAMP('2017-05-05 14:45:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_RelationType_ID=540178 +; + + + +-- 2017-05-05T16:05:41.973 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_RelationType SET IsActive='N', Name='C_Order -> MD_Candidate_all',Updated=TO_TIMESTAMP('2017-05-05 16:05:41','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_RelationType_ID=540178 +; + +-- 2017-05-05T16:06:06.198 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Ref_Table SET EntityType='de.metas.material.dispo',Updated=TO_TIMESTAMP('2017-05-05 16:06:06','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Reference_ID=540721 +; + diff --git a/de.metas.material/dispo/src/main/sql/postgresql/system/5461810_sys_gh523-metasfresh_polish_md_candidate.sql b/de.metas.material/dispo/src/main/sql/postgresql/system/5461810_sys_gh523-metasfresh_polish_md_candidate.sql new file mode 100644 index 00000000000..d38d80b503f --- /dev/null +++ b/de.metas.material/dispo/src/main/sql/postgresql/system/5461810_sys_gh523-metasfresh_polish_md_candidate.sql @@ -0,0 +1,97 @@ +-- 2017-05-04T17:02:25.838 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Column SET IsSelectionColumn='Y',Updated=TO_TIMESTAMP('2017-05-04 17:02:25','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=556510 +; + +-- 2017-05-04T17:02:39.799 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Column SET IsSelectionColumn='Y', IsUpdateable='N',Updated=TO_TIMESTAMP('2017-05-04 17:02:39','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=556483 +; + +-- 2017-05-04T17:03:22.060 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Column SET AllowZoomTo='Y', IsUpdateable='N',Updated=TO_TIMESTAMP('2017-05-04 17:03:22','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=556483 +; + + + +-- 2017-05-05T12:22:20.222 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Ref_List SET Name='Beleg erstellt', Value='doc_created', ValueName='doc_created',Updated=TO_TIMESTAMP('2017-05-05 12:22:20','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Ref_List_ID=541267 +; + +-- 2017-05-05T12:22:20.231 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Ref_List_Trl SET IsTranslated='N' WHERE AD_Ref_List_ID=541267 +; + +-- 2017-05-05T12:22:49.414 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Ref_List (AD_Client_ID,AD_Org_ID,AD_Ref_List_ID,AD_Reference_ID,Created,CreatedBy,EntityType,IsActive,Name,Updated,UpdatedBy,Value,ValueName) VALUES (0,0,541270,540715,TO_TIMESTAMP('2017-05-05 12:22:49','YYYY-MM-DD HH24:MI:SS'),100,'de.metas.material.dispo','Y','Beleg fertiggestellt',TO_TIMESTAMP('2017-05-05 12:22:49','YYYY-MM-DD HH24:MI:SS'),100,'doc_completed','doc_completed') +; + +-- 2017-05-05T12:22:49.419 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Ref_List_Trl (AD_Language,AD_Ref_List_ID, Description,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Ref_List_ID, t.Description,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Ref_List t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Ref_List_ID=541270 AND NOT EXISTS (SELECT * FROM AD_Ref_List_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Ref_List_ID=t.AD_Ref_List_ID) +; + +-- 2017-05-05T12:23:08.493 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Ref_List (AD_Client_ID,AD_Org_ID,AD_Ref_List_ID,AD_Reference_ID,Created,CreatedBy,EntityType,IsActive,Name,Updated,UpdatedBy,Value,ValueName) VALUES (0,0,541271,540715,TO_TIMESTAMP('2017-05-05 12:23:08','YYYY-MM-DD HH24:MI:SS'),100,'U','Y','Beleg geschlossen',TO_TIMESTAMP('2017-05-05 12:23:08','YYYY-MM-DD HH24:MI:SS'),100,'doc_closed','doc_closed') +; + +-- 2017-05-05T12:23:08.496 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO AD_Ref_List_Trl (AD_Language,AD_Ref_List_ID, Description,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Ref_List_ID, t.Description,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Ref_List t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Ref_List_ID=541271 AND NOT EXISTS (SELECT * FROM AD_Ref_List_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Ref_List_ID=t.AD_Ref_List_ID) +; + +-- 2017-05-05T12:39:25.256 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Ref_List SET Name='Beleg geplant', Value='doc_planned', ValueName='doc_planned',Updated=TO_TIMESTAMP('2017-05-05 12:39:25','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Ref_List_ID=541268 +; + +-- 2017-05-05T12:39:25.259 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Ref_List_Trl SET IsTranslated='N' WHERE AD_Ref_List_ID=541268 +; + +-- 2017-05-05T12:39:34.527 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Ref_List SET EntityType='de.metas.material.dispo',Updated=TO_TIMESTAMP('2017-05-05 12:39:34','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Ref_List_ID=541271 +; + +-- 2017-05-05T12:40:08.857 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Field SET IsReadOnly='Y',Updated=TO_TIMESTAMP('2017-05-05 12:40:08','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=558150 +; + +-- 2017-05-05T12:40:14.431 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Field SET IsReadOnly='Y',Updated=TO_TIMESTAMP('2017-05-05 12:40:14','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=558148 +; + +-- 2017-05-05T12:40:19.431 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Field SET IsReadOnly='Y',Updated=TO_TIMESTAMP('2017-05-05 12:40:19','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=558147 +; + +-- 2017-05-05T12:40:28.479 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Field SET IsDisplayed='N', IsDisplayedGrid='N', IsReadOnly='Y',Updated=TO_TIMESTAMP('2017-05-05 12:40:28','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=558149 +; + +-- 2017-05-05T12:40:35.032 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Field SET IsDisplayed='N', IsDisplayedGrid='N',Updated=TO_TIMESTAMP('2017-05-05 12:40:35','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=558146 +; + + +-- 2017-05-05T16:03:09.663 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +UPDATE AD_Column SET FieldLength=15,Updated=TO_TIMESTAMP('2017-05-05 16:03:09','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=556512 +; + +-- 2017-05-05T16:03:13.744 +-- I forgot to set the DICTIONARY_ID_COMMENTS System Configurator +INSERT INTO t_alter_column values('md_candidate','MD_Candidate_Status','VARCHAR(15)',null,null) +; diff --git a/de.metas.material/dispo/src/test/java/de/metas/material/dispo/CandiateRepositoryTests.java b/de.metas.material/dispo/src/test/java/de/metas/material/dispo/CandiateRepositoryTests.java index 5635ac239d7..9dec8cff65a 100644 --- a/de.metas.material/dispo/src/test/java/de/metas/material/dispo/CandiateRepositoryTests.java +++ b/de.metas.material/dispo/src/test/java/de/metas/material/dispo/CandiateRepositoryTests.java @@ -1,10 +1,13 @@ package de.metas.material.dispo; +import static org.adempiere.model.InterfaceWrapperHelper.newInstance; +import static org.adempiere.model.InterfaceWrapperHelper.save; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; import java.math.BigDecimal; @@ -20,8 +23,11 @@ import org.adempiere.test.AdempiereTestHelper; import org.adempiere.test.AdempiereTestWatcher; import org.adempiere.util.Services; +import org.adempiere.util.lang.IPair; +import org.adempiere.util.lang.ImmutablePair; import org.adempiere.util.lang.impl.TableRecordReference; import org.adempiere.util.time.SystemTime; +import org.compiere.model.I_AD_Org; import org.compiere.model.I_C_UOM; import org.compiere.model.I_M_Product; import org.compiere.model.I_M_Warehouse; @@ -36,6 +42,7 @@ import de.metas.material.dispo.Candidate.Type; import de.metas.material.dispo.CandidatesSegment.DateOperator; import de.metas.material.dispo.model.I_MD_Candidate; +import de.metas.material.dispo.model.I_MD_Candidate_Demand_Detail; import de.metas.material.dispo.model.I_MD_Candidate_Prod_Detail; import de.metas.material.dispo.model.X_MD_Candidate; @@ -78,6 +85,8 @@ public class CandiateRepositoryTests private I_C_UOM uom; + private I_AD_Org org; + private Candidate stockCandidate; private Candidate laterStockCandidate; @@ -88,45 +97,48 @@ public void init() { AdempiereTestHelper.get().init(); - product = InterfaceWrapperHelper.newInstance(I_M_Product.class); - InterfaceWrapperHelper.save(product); + org = newInstance(I_AD_Org.class); + save(org); + + product = newInstance(I_M_Product.class); + save(product); - warehouse = InterfaceWrapperHelper.newInstance(I_M_Warehouse.class); - InterfaceWrapperHelper.save(warehouse); + warehouse = newInstance(I_M_Warehouse.class); + save(warehouse); - uom = InterfaceWrapperHelper.newInstance(I_C_UOM.class); - InterfaceWrapperHelper.save(uom); + uom = newInstance(I_C_UOM.class); + save(uom); // this not-stock candidate needs to be ignored final Candidate someOtherCandidate = Candidate.builder() .type(Type.DEMAND) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(new BigDecimal("11")) .date(now) .build(); - candidateRepository.addOrReplace(someOtherCandidate); + candidateRepository.addOrUpdate(someOtherCandidate); stockCandidate = Candidate.builder() .type(Type.STOCK) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(new BigDecimal("10")) .date(now) .build(); - stockCandidate = candidateRepository.addOrReplace(stockCandidate); + stockCandidate = candidateRepository.addOrUpdate(stockCandidate); laterStockCandidate = Candidate.builder() .type(Type.STOCK) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(new BigDecimal("10")) .date(later) .build(); - laterStockCandidate = candidateRepository.addOrReplace(laterStockCandidate); + laterStockCandidate = candidateRepository.addOrUpdate(laterStockCandidate); } /** @@ -143,7 +155,7 @@ public void addOrReplace_update() assertThat(stockBeforeReplacement.stream().collect(Collectors.toList()), contains(stockCandidate, laterStockCandidate)); final Candidate replacementCandidate = stockCandidate.withQuantity(BigDecimal.ONE); - candidateRepository.addOrReplace(replacementCandidate); + candidateRepository.addOrUpdate(replacementCandidate); assertThat(candidateRepository.retrieveLatestMatch(mkStockUntilSegment(now)).get(), is(replacementCandidate)); final List stockAfterReplacement = candidateRepository.retrieveMatches(mkStockFromSegment(now)); @@ -161,7 +173,7 @@ public void addOrReplace_with_ProductionDetail() .type(Type.DEMAND) .subType(SubType.PRODUCTION) .date(now) - .orgId(20) + .orgId(org.getAD_Org_ID()) .productId(23) .attributeSetInstanceId(35) .quantity(BigDecimal.TEN) @@ -178,7 +190,7 @@ public void addOrReplace_with_ProductionDetail() .ppOrderDocStatus("ppOrderDocStatus") .build()) .build(); - final Candidate addOrReplaceResult = candidateRepository.addOrReplace(productionCandidate); + final Candidate addOrReplaceResult = candidateRepository.addOrUpdate(productionCandidate); final List filtered = DispoTestUtils.filter(Type.DEMAND, now, 23); assertThat(filtered.size(), is(1)); @@ -203,15 +215,20 @@ public void addOrReplace_with_ProductionDetail() @Test public void retrieve_with_ProductionDetail() { - final I_MD_Candidate record = InterfaceWrapperHelper.newInstance(I_MD_Candidate.class); + perform_retrieve_with_ProductionDetail(); + } + + private IPair perform_retrieve_with_ProductionDetail() + { + final I_MD_Candidate record = newInstance(I_MD_Candidate.class); record.setM_Product_ID(24); record.setM_Warehouse_ID(51); record.setDateProjected(new Timestamp(now.getTime())); record.setMD_Candidate_Type(X_MD_Candidate.MD_CANDIDATE_TYPE_DEMAND); record.setMD_Candidate_SubType(X_MD_Candidate.MD_CANDIDATE_SUBTYPE_PRODUCTION); - InterfaceWrapperHelper.save(record); + save(record); - final I_MD_Candidate_Prod_Detail productionDetailRecord = InterfaceWrapperHelper.newInstance(I_MD_Candidate_Prod_Detail.class); + final I_MD_Candidate_Prod_Detail productionDetailRecord = newInstance(I_MD_Candidate_Prod_Detail.class); productionDetailRecord.setDescription("description1"); productionDetailRecord.setPP_Plant_ID(61); productionDetailRecord.setPP_Product_BOMLine_ID(71); @@ -221,7 +238,7 @@ public void retrieve_with_ProductionDetail() productionDetailRecord.setPP_Order_ID(101); productionDetailRecord.setPP_Order_BOMLine_ID(111); productionDetailRecord.setPP_Order_DocStatus("ppOrderDocStatus1"); - InterfaceWrapperHelper.save(productionDetailRecord); + save(productionDetailRecord); final Candidate cand = candidateRepository.retrieve(record.getMD_Candidate_ID()); assertThat(cand, notNullValue()); @@ -236,6 +253,132 @@ public void retrieve_with_ProductionDetail() assertThat(cand.getProductionDetail().getPpOrderId(), is(101)); assertThat(cand.getProductionDetail().getPpOrderLineId(), is(111)); assertThat(cand.getProductionDetail().getPpOrderDocStatus(), is("ppOrderDocStatus1")); + + return ImmutablePair.of(cand, record); + } + + /** + * Verifies that demand details are also used as filter criterion + * If this one fails, i recommend to first check if {@link #retrieve_with_ProductionDetail()} works. + */ + @Test + public void retrieve_with_ProductionDetail_filtered() + { + final IPair pair = perform_retrieve_with_ProductionDetail(); + final Candidate cand = pair.getLeft(); + final I_MD_Candidate record = pair.getRight(); + + // make another record, just like "record", but without a demandDetailRecord + final I_MD_Candidate otherRecord = newInstance(I_MD_Candidate.class); + otherRecord.setM_Product_ID(24); + otherRecord.setM_Warehouse_ID(51); + otherRecord.setDateProjected(new Timestamp(now.getTime())); + otherRecord.setMD_Candidate_Type(X_MD_Candidate.MD_CANDIDATE_TYPE_DEMAND); + otherRecord.setMD_Candidate_SubType(X_MD_Candidate.MD_CANDIDATE_SUBTYPE_PRODUCTION); + save(otherRecord); + + final Optional expectedRecordWithProdDetails = candidateRepository.retrieveExact(cand); + assertThat(expectedRecordWithProdDetails.isPresent(), is(true)); + assertThat(expectedRecordWithProdDetails.get().getMD_Candidate_ID(), is(record.getMD_Candidate_ID())); + + final Optional expectedRecordWithoutProdDetails = candidateRepository.retrieveExact(cand.withProductionDetail(null)); + assertThat(expectedRecordWithoutProdDetails.isPresent(), is(true)); + assertThat(expectedRecordWithoutProdDetails.get().getMD_Candidate_ID(), is(otherRecord.getMD_Candidate_ID())); + } + + @Test + public void addOrReplace_with_DemandDetail() + { + final Candidate productionCandidate = Candidate.builder() + .type(Type.DEMAND) + .subType(SubType.SHIPMENT) + .date(now) + .orgId(org.getAD_Org_ID()) + .productId(23) + .attributeSetInstanceId(35) + .quantity(BigDecimal.TEN) + .reference(TableRecordReference.of("someTable", 40)) + .warehouseId(50) + .demandDetail(DemandCandidateDetail.builder() + .orderLineId(61) + .build()) + .build(); + final Candidate addOrReplaceResult = candidateRepository.addOrUpdate(productionCandidate); + + final List filtered = DispoTestUtils.filter(Type.DEMAND, now, 23); + assertThat(filtered.size(), is(1)); + + final I_MD_Candidate record = filtered.get(0); + assertThat(record.getMD_Candidate_ID(), is(addOrReplaceResult.getId())); + assertThat(record.getMD_Candidate_SubType(), is(productionCandidate.getSubType().toString())); + assertThat(record.getM_Product_ID(), is(productionCandidate.getProductId())); + + final I_MD_Candidate_Demand_Detail demandDetailRecord = Services.get(IQueryBL.class).createQueryBuilder(I_MD_Candidate_Demand_Detail.class).create().firstOnly(I_MD_Candidate_Demand_Detail.class); + assertThat(demandDetailRecord, notNullValue()); + assertThat(demandDetailRecord.getC_OrderLine_ID(), is(61)); + } + + @Test + public void retrieve_with_DemandDetail() + { + perform_retrieve_with_DemandDetail(); + } + + private IPair perform_retrieve_with_DemandDetail() + { + final I_MD_Candidate record = newInstance(I_MD_Candidate.class); + record.setM_Product_ID(24); + record.setM_Warehouse_ID(51); + record.setDateProjected(new Timestamp(now.getTime())); + record.setMD_Candidate_Type(X_MD_Candidate.MD_CANDIDATE_TYPE_DEMAND); + record.setMD_Candidate_SubType(X_MD_Candidate.MD_CANDIDATE_SUBTYPE_PRODUCTION); + save(record); + + final I_MD_Candidate_Demand_Detail demandDetailRecord = newInstance(I_MD_Candidate_Demand_Detail.class); + demandDetailRecord.setMD_Candidate(record); + demandDetailRecord.setC_OrderLine_ID(62); + save(demandDetailRecord); + + final Candidate cand = candidateRepository.retrieve(record.getMD_Candidate_ID()); + assertThat(cand, notNullValue()); + assertThat(cand.getProductId(), is(24)); + assertThat(cand.getWarehouseId(), is(51)); + assertThat(cand.getDate(), is(now)); + assertThat(cand.getProductionDetail(), nullValue()); + assertThat(cand.getDemandDetail().getOrderLineId(), is(62)); + + return ImmutablePair.of(cand, record); + } + + /** + * Verifies that demand details are also used as filter criterion + * If this one fails, i recommend to first check if {@link #retrieve_with_DemandDetail()} works + */ + @Test + public void retrieve_with_DemandDetail_filtered() + { + final IPair pair = perform_retrieve_with_DemandDetail(); + final Candidate cand = pair.getLeft(); + final I_MD_Candidate record = pair.getRight(); + + // make another record, just like "record", but without a demandDetailRecord + final I_MD_Candidate otherRecord = newInstance(I_MD_Candidate.class); + otherRecord.setM_Product_ID(24); + otherRecord.setM_Warehouse_ID(51); + otherRecord.setDateProjected(new Timestamp(now.getTime())); + otherRecord.setMD_Candidate_Type(X_MD_Candidate.MD_CANDIDATE_TYPE_DEMAND); + otherRecord.setMD_Candidate_SubType(X_MD_Candidate.MD_CANDIDATE_SUBTYPE_PRODUCTION); + save(otherRecord); + + final Optional expectedRecordWithDemandDetails = candidateRepository.retrieveExact(cand); + assertThat(expectedRecordWithDemandDetails.isPresent(), is(true)); + assertThat(expectedRecordWithDemandDetails.get().getMD_Candidate_ID(), is(record.getMD_Candidate_ID())); + + final Optional expectedRecordWithoutDemandDetails = candidateRepository + .retrieveExact(cand.withDemandDetail(DemandCandidateDetail.builder().orderLineId(DemandCandidateDetail.NO_ORDERLINE_ID).build())); + + assertThat(expectedRecordWithoutDemandDetails.isPresent(), is(true)); + assertThat(expectedRecordWithoutDemandDetails.get().getMD_Candidate_ID(), is(otherRecord.getMD_Candidate_ID())); } /** @@ -250,7 +393,7 @@ public void addOrReplace_groupId_nonStockCandidate() .withDate(TimeUtil.addMinutes(later, 1)) // pick a different time from the other candidates .withGroupId(null); - final Candidate result1 = candidateRepository.addOrReplace(candidateWithOutGroupId); + final Candidate result1 = candidateRepository.addOrUpdate(candidateWithOutGroupId); // result1 was assigned an id and a groupId assertThat(result1.getId(), greaterThan(0)); assertThat(result1.getGroupId(), is(result1.getId())); @@ -259,7 +402,7 @@ public void addOrReplace_groupId_nonStockCandidate() .withDate(TimeUtil.addMinutes(later, 2)) // pick a different time from the other candidates .withGroupId(result1.getGroupId()); - final Candidate result2 = candidateRepository.addOrReplace(candidateWithGroupId); + final Candidate result2 = candidateRepository.addOrUpdate(candidateWithGroupId); // result2 also has id & groupId, but its ID is unique whereas its groupId is the same as result1's groupId assertThat(result2.getId(), greaterThan(0)); assertThat(result2.getGroupId(), not(is(result2.getId()))); @@ -284,7 +427,7 @@ public void addOrReplace_groupId_stockCandidate() .withDate(TimeUtil.addMinutes(later, 1)) // pick a different time from the other candidates .withGroupId(null); - final Candidate result1 = candidateRepository.addOrReplace(candidateWithOutGroupId); + final Candidate result1 = candidateRepository.addOrUpdate(candidateWithOutGroupId); assertThat(result1.getId(), greaterThan(0)); assertThat(result1.getGroupId(), greaterThan(0)); @@ -324,6 +467,8 @@ public void retrieveStockAt() // return candidate.withId(null).withParentId(null); // } + // TODO: make sure that AD_Client_ID is set correctly from AD_Org + @Test public void retrieveStockFrom() { diff --git a/de.metas.material/dispo/src/test/java/de/metas/material/dispo/CandidateChangeHandlerTests.java b/de.metas.material/dispo/src/test/java/de/metas/material/dispo/CandidateChangeHandlerTests.java index 1c034957543..1da1b74d731 100644 --- a/de.metas.material/dispo/src/test/java/de/metas/material/dispo/CandidateChangeHandlerTests.java +++ b/de.metas.material/dispo/src/test/java/de/metas/material/dispo/CandidateChangeHandlerTests.java @@ -1,5 +1,7 @@ package de.metas.material.dispo; +import static org.adempiere.model.InterfaceWrapperHelper.newInstance; +import static org.adempiere.model.InterfaceWrapperHelper.save; import static org.hamcrest.Matchers.comparesEqualTo; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.is; @@ -20,6 +22,7 @@ import org.adempiere.util.Services; import org.adempiere.util.lang.impl.TableRecordReference; import org.adempiere.util.time.SystemTime; +import org.compiere.model.I_AD_Org; import org.compiere.model.I_C_UOM; import org.compiere.model.I_M_Product; import org.compiere.model.I_M_Warehouse; @@ -70,6 +73,8 @@ public class CandidateChangeHandlerTests private final Date t3 = TimeUtil.addMinutes(t1, 20); private final Date t4 = TimeUtil.addMinutes(t1, 30); + private I_AD_Org org; + private I_M_Product product; private I_M_Warehouse warehouse; @@ -89,6 +94,9 @@ public void init() { AdempiereTestHelper.get().init(); + org = newInstance(I_AD_Org.class); + save(org); + product = InterfaceWrapperHelper.newInstance(I_M_Product.class); InterfaceWrapperHelper.save(product); @@ -124,18 +132,18 @@ public void testApplyDeltaToLaterStockCandidates() { candidate = Candidate.builder() .type(Type.STOCK) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(new BigDecimal("10")) .date(t2) .build(); - candidateRepository.addOrReplace(candidate); + candidateRepository.addOrUpdate(candidate); earlierCandidate = candidateRepository - .addOrReplace(Candidate.builder() + .addOrUpdate(Candidate.builder() .type(Type.STOCK) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(new BigDecimal("10")) @@ -144,33 +152,33 @@ public void testApplyDeltaToLaterStockCandidates() final Candidate laterCandidate = Candidate.builder() .type(Type.STOCK) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(new BigDecimal("10")) .date(t3) .build(); - candidateRepository.addOrReplace(laterCandidate); + candidateRepository.addOrUpdate(laterCandidate); evenLaterCandidate = Candidate.builder() .type(Type.STOCK) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(new BigDecimal("12")) .date(t4) .build(); - candidateRepository.addOrReplace(evenLaterCandidate); + candidateRepository.addOrUpdate(evenLaterCandidate); evenLaterCandidateWithDifferentWarehouse = Candidate.builder() .type(Type.STOCK) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(otherWarehouse.getM_Warehouse_ID()) .quantity(new BigDecimal("12")) .date(t4) .build(); - candidateRepository.addOrReplace(evenLaterCandidateWithDifferentWarehouse); + candidateRepository.addOrUpdate(evenLaterCandidateWithDifferentWarehouse); } // do the test @@ -308,13 +316,13 @@ private Candidate invokeUpdateStock(final Date t, final BigDecimal qty) { final Candidate candidate = Candidate.builder() .type(Type.STOCK) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(qty) .date(t) .build(); - final Candidate processedCandidate = candidateChangeHandler.updateStock(candidate); + final Candidate processedCandidate = candidateChangeHandler.addOrUpdateStock(candidate); return processedCandidate; } @@ -395,21 +403,21 @@ public List retrieveAllRecordsSorted() } /** - * Verifies that {@link CandidateChangeHandler#updateStock(Candidate)} also works if the candidate we update with is not a stock candidate. + * Verifies that {@link CandidateChangeHandler#addOrUpdateStock(Candidate)} also works if the candidate we update with is not a stock candidate. */ @Test public void testOnStockCandidateNewOrChangedNotStockType() { final Candidate candidate = Candidate.builder() .type(Type.SUPPLY) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(new BigDecimal("10")) .date(t2) .build(); - final Candidate processedCandidate = candidateChangeHandler.updateStock(candidate); + final Candidate processedCandidate = candidateChangeHandler.addOrUpdateStock(candidate); assertThat(processedCandidate.getType(), is(Type.STOCK)); assertThat(processedCandidate.getDate().getTime(), is(t2.getTime())); assertThat(processedCandidate.getQuantity(), comparesEqualTo(BigDecimal.TEN)); @@ -425,7 +433,7 @@ public void testOnSupplyCandidateNewOrChange_noOlderRecords() final Candidate candidate = Candidate.builder() .type(Type.SUPPLY) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(qty) @@ -452,7 +460,7 @@ public void testOnSupplyCandidateNewOrChange_noOlderRecords_invokeTwiceWithSame( final Candidate candidatee = Candidate.builder() .type(Type.SUPPLY) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(qty) @@ -487,7 +495,7 @@ public void testOnSupplyCandidateNewOrChange_noOlderRecords_invokeTwiceWithDiffe final Candidate candidatee = Candidate.builder() .type(Type.SUPPLY) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(qty) @@ -524,19 +532,19 @@ public void testOnSupplyCandidateNewOrChange() final Candidate olderStockCandidate = Candidate.builder() .type(Type.STOCK) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(olderStockQty) .date(t1) .build(); - candidateChangeHandler.updateStock(olderStockCandidate); + candidateChangeHandler.addOrUpdateStock(olderStockCandidate); final BigDecimal supplyQty = new BigDecimal("23"); final Candidate candidate = Candidate.builder() .type(Type.SUPPLY) - .orgId(1) + .orgId(org.getAD_Org_ID()) .subType(SubType.PRODUCTION) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) @@ -566,7 +574,7 @@ public void testOnDemandCandidateCandidateNewOrChange_noOlderRecords() final Candidate candidate = Candidate.builder() .type(Type.DEMAND) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(qty) @@ -598,7 +606,7 @@ public void testDemandCandidateThenSupplyCandidate() final Candidate candidate = Candidate.builder() .type(Type.DEMAND) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(qty) @@ -611,7 +619,7 @@ public void testDemandCandidateThenSupplyCandidate() final Candidate supplyCandidate = Candidate.builder() .type(Type.SUPPLY) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(qty) @@ -648,7 +656,7 @@ public void testSupplyCandidateThenDemandCandidate() final Candidate supplyCandidate = Candidate.builder() .type(Type.SUPPLY) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(qty) @@ -668,7 +676,7 @@ public void testSupplyCandidateThenDemandCandidate() final Candidate demandCandidate = Candidate.builder() .type(Type.DEMAND) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(qty) @@ -703,7 +711,7 @@ public void testOnDemandCandidateCandidateNewOrChange_noOlderRecords_invokeTwice final Candidate candidatee = Candidate.builder() .type(Type.DEMAND) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(qty) @@ -742,7 +750,7 @@ public void testOnDemandCandidateCandidateNewOrChange_noOlderRecords_invokeTwice final Candidate candidatee = Candidate.builder() .type(Type.DEMAND) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(qty) diff --git a/de.metas.material/dispo/src/test/java/de/metas/material/dispo/CandidateFactoryTests.java b/de.metas.material/dispo/src/test/java/de/metas/material/dispo/CandidateFactoryTests.java index 7dd6009a1b6..b107128fd32 100644 --- a/de.metas.material/dispo/src/test/java/de/metas/material/dispo/CandidateFactoryTests.java +++ b/de.metas.material/dispo/src/test/java/de/metas/material/dispo/CandidateFactoryTests.java @@ -1,5 +1,7 @@ package de.metas.material.dispo; +import static org.adempiere.model.InterfaceWrapperHelper.newInstance; +import static org.adempiere.model.InterfaceWrapperHelper.save; import static org.hamcrest.Matchers.comparesEqualTo; import static org.junit.Assert.assertThat; @@ -9,6 +11,7 @@ import org.adempiere.model.InterfaceWrapperHelper; import org.adempiere.test.AdempiereTestHelper; import org.adempiere.util.time.SystemTime; +import org.compiere.model.I_AD_Org; import org.compiere.model.I_C_UOM; import org.compiere.model.I_M_Product; import org.compiere.model.I_M_Warehouse; @@ -46,6 +49,8 @@ public class CandidateFactoryTests private final Date earlier = TimeUtil.addMinutes(now, -10); private final Date later = TimeUtil.addMinutes(now, 10); + private I_AD_Org org; + private I_C_UOM uom; private I_M_Product product; @@ -61,6 +66,9 @@ public void init() { AdempiereTestHelper.get().init(); + org = newInstance(I_AD_Org.class); + save(org); + uom = InterfaceWrapperHelper.newInstance(I_C_UOM.class); InterfaceWrapperHelper.save(uom); @@ -73,16 +81,16 @@ public void init() candidateRepository = new CandidateRepository(); candidateFactory = new CandidateFactory(candidateRepository); - + final Candidate stockCandidate = Candidate.builder() .type(Type.STOCK) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .quantity(new BigDecimal("10")) .date(now) .build(); - candidateRepository.addOrReplace(stockCandidate); + candidateRepository.addOrUpdate(stockCandidate); } /** @@ -93,7 +101,7 @@ public void createStockCandidate_before_existing() { final Candidate candidate = Candidate.builder() .type(Type.STOCK) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .date(earlier) @@ -112,7 +120,7 @@ public void createStockCandidate_after_existing() { final Candidate candidate = Candidate.builder() .type(Type.STOCK) - .orgId(1) + .orgId(org.getAD_Org_ID()) .productId(product.getM_Product_ID()) .warehouseId(warehouse.getM_Warehouse_ID()) .date(later) diff --git a/de.metas.material/dispo/src/test/java/de/metas/material/dispo/CandidateServiceTests.java b/de.metas.material/dispo/src/test/java/de/metas/material/dispo/CandidateServiceTests.java index a95bebc7136..f865f68ae5e 100644 --- a/de.metas.material/dispo/src/test/java/de/metas/material/dispo/CandidateServiceTests.java +++ b/de.metas.material/dispo/src/test/java/de/metas/material/dispo/CandidateServiceTests.java @@ -14,7 +14,8 @@ import de.metas.material.dispo.Candidate.SubType; import de.metas.material.dispo.Candidate.Type; -import de.metas.material.event.ProductionOrderRequested; +import de.metas.material.event.MaterialEventService; +import de.metas.material.event.PPOrderRequestedEvent; import de.metas.material.event.pporder.PPOrder; /* @@ -27,12 +28,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -79,8 +80,9 @@ public void testReqestPPOrder() .productBomLineId(600) .build()); - final CandidateService candidateService = new CandidateService(candidateRepository); - final ProductionOrderRequested productionOrderEvent = candidateService.requestProductionOrder(ImmutableList.of(candidate, candidate2, candidate3)); + final CandidateService candidateService = new CandidateService(candidateRepository, new MaterialEventService(de.metas.event.Type.LOCAL)); + + final PPOrderRequestedEvent productionOrderEvent = candidateService.createRequestEvent(ImmutableList.of(candidate, candidate2, candidate3)); assertThat(productionOrderEvent, notNullValue()); final PPOrder ppOrder = productionOrderEvent.getPpOrder(); diff --git a/de.metas.material/dispo/src/test/java/de/metas/material/dispo/event/DistributionPlanEventHandlerTests.java b/de.metas.material/dispo/src/test/java/de/metas/material/dispo/event/DistributionPlanEventHandlerTests.java new file mode 100644 index 00000000000..c868d891a4f --- /dev/null +++ b/de.metas.material/dispo/src/test/java/de/metas/material/dispo/event/DistributionPlanEventHandlerTests.java @@ -0,0 +1,301 @@ +package de.metas.material.dispo.event; + +import static org.adempiere.model.InterfaceWrapperHelper.newInstance; +import static org.adempiere.model.InterfaceWrapperHelper.save; +import static org.hamcrest.Matchers.comparesEqualTo; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.lessThanOrEqualTo; +import static org.junit.Assert.assertThat; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +import org.adempiere.test.AdempiereTestHelper; +import org.adempiere.test.AdempiereTestWatcher; +import org.adempiere.util.lang.impl.TableRecordReference; +import org.adempiere.util.time.SystemTime; +import org.compiere.model.I_AD_Org; +import org.compiere.util.TimeUtil; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestWatcher; + +import de.metas.material.dispo.Candidate.Type; +import de.metas.material.dispo.CandidateChangeHandler; +import de.metas.material.dispo.CandidateFactory; +import de.metas.material.dispo.CandidateRepository; +import de.metas.material.dispo.DispoTestUtils; +import de.metas.material.dispo.model.I_MD_Candidate; +import de.metas.material.event.DistributionPlanEvent; +import de.metas.material.event.EventDescr; +import de.metas.material.event.MaterialDescriptor; +import de.metas.material.event.MaterialEventService; +import lombok.NonNull; +import mockit.Mocked; + +/* + * #%L + * metasfresh-material-dispo + * %% + * Copyright (C) 2017 metas GmbH + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +public class DistributionPlanEventHandlerTests +{ + /** Watches the current tests and dumps the database to console in case of failure */ + @Rule + public final TestWatcher testWatcher = new AdempiereTestWatcher(); + + public static final Date t0 = SystemTime.asDate(); + + private static final Date t1 = TimeUtil.addMinutes(t0, 10); + + private static final Date t2 = TimeUtil.addMinutes(t0, 20); + + private static final Date t3 = TimeUtil.addMinutes(t0, 30); + + public static final int fromWarehouseId = 10; + public static final int intermediateWarehouseId = 20; + public static final int toWarehouseId = 30; + + public static final int productId = 40; + + public static final int rawProduct1Id = 50; + + public static final int rawProduct2Id = 55; + + private I_AD_Org org; + + private DistributionPlanEventHandler distributionPlanEventHandler; + + @Mocked + private MaterialEventService materialEventService; + + @Before + public void init() + { + AdempiereTestHelper.get().init(); + + org = newInstance(I_AD_Org.class); + save(org); + + final CandidateRepository candidateRepository = new CandidateRepository(); + final SupplyProposalEvaluator supplyProposalEvaluator = new SupplyProposalEvaluator(candidateRepository); + + distributionPlanEventHandler = new DistributionPlanEventHandler( + candidateRepository, + new CandidateChangeHandler(candidateRepository, new CandidateFactory(candidateRepository), materialEventService), + supplyProposalEvaluator); + } + + /** + * Verifies that for a {@link DistributionPlanEvent}, the system shall (unless the event is ignored for different reasons!) create two pairs of candidate records: + *

      + *
    • one supply-pair with a supply candidate and its stock parent
    • + *
    • one demand-pair with a demand candidate and its stock child
    • + *
    + */ + @Test + public void testSingleDistibutionPlanEvent() + { + final TableRecordReference reference = TableRecordReference.of("someTable", 4); + final DistributionPlanEvent event = DistributionPlanEvent.builder() + .eventDescr(new EventDescr()) + .distributionStart(t1) + .fromWarehouseId(fromWarehouseId) + .materialDescr(MaterialDescriptor.builder() + .date(t2) + .orgId(org.getAD_Org_ID()) + .productId(productId) + .qty(BigDecimal.TEN) + .warehouseId(toWarehouseId) + .build()) + .reference(reference) + .build(); + distributionPlanEventHandler.handleDistributionPlanEvent(event); + + final List allRecords = DispoTestUtils.retrieveAllRecords(); + assertThat(allRecords.size(), is(4)); + + // all four shall have the same product + allRecords.forEach(r -> { + assertThat(r.getM_Product_ID(), is(productId)); + }); + + // all four shall have the same org + allRecords.forEach(r -> { + assertThat(r.getAD_Org_ID(), is(org.getAD_Org_ID())); + }); + + // all four shall have the same reference + allRecords.forEach(r -> { + final TableRecordReference ofReferenced = TableRecordReference.ofReferenced(r); + assertThat(ofReferenced, is(reference)); + }); + + assertThat(DispoTestUtils.filter(Type.SUPPLY).size(), is(1)); + assertThat(DispoTestUtils.filter(Type.STOCK).size(), is(2)); + assertThat(DispoTestUtils.filter(Type.DEMAND).size(), is(1)); + + // supplyStockRecord is the parent record of supplyRecord + final I_MD_Candidate supplyStockRecord = DispoTestUtils.filter(Type.STOCK, t2).get(0); + assertThat(supplyStockRecord.getMD_Candidate_Type(), is(Type.STOCK.toString())); + assertThat(supplyStockRecord.getMD_Candidate_Parent_ID(), lessThanOrEqualTo(0)); // supplyStockRecord shall have no parent of its own + assertThat(supplyStockRecord.getQty(), comparesEqualTo(BigDecimal.TEN)); + assertThat(supplyStockRecord.getDateProjected().getTime(), is(t2.getTime())); // shall have the same time as its supply record + assertThat(supplyStockRecord.getM_Warehouse_ID(), is(toWarehouseId)); // shall have the same wh as its supply record + + final I_MD_Candidate supplyRecord = DispoTestUtils.filter(Type.SUPPLY).get(0); + assertThat(supplyRecord.getMD_Candidate_Parent_ID(), is(supplyStockRecord.getMD_Candidate_ID())); + assertThat(supplyRecord.getDateProjected().getTime(), is(t2.getTime())); + assertThat(supplyRecord.getM_Warehouse_ID(), is(toWarehouseId)); + assertThat(supplyRecord.getQty(), comparesEqualTo(BigDecimal.TEN)); + assertThat(supplyRecord.getMD_Candidate_Parent_ID() > 0, is(true)); // supplyRecord shall have supplyStockRecord as its parent + + final I_MD_Candidate demandRecord = DispoTestUtils.filter(Type.DEMAND).get(0); + assertThat(demandRecord.getDateProjected().getTime(), is(t1.getTime())); + assertThat(demandRecord.getMD_Candidate_Parent_ID(), is(supplyRecord.getMD_Candidate_ID())); // demandRecord shall have supplyRecord as its parent + assertThat(demandRecord.getM_Warehouse_ID(), is(fromWarehouseId)); + assertThat(demandRecord.getQty(), comparesEqualTo(BigDecimal.TEN)); + + // demandStockRecord is "the other" stock record + final I_MD_Candidate demandStockRecord = DispoTestUtils.filter(Type.STOCK, t1).get(0); + assertThat(demandStockRecord.getMD_Candidate_Parent_ID(), is(demandRecord.getMD_Candidate_ID())); + assertThat(demandStockRecord.getDateProjected().getTime(), is(t1.getTime())); // demandStockRecord shall have the same time as its demand record + assertThat(demandStockRecord.getM_Warehouse_ID(), is(fromWarehouseId)); + assertThat(demandStockRecord.getQty(), comparesEqualTo(BigDecimal.TEN.negate())); + + // for display reasons we expect the MD_Candidate_IDs to have a strict order, i.e. demand - stock - supply - demand etc.. + assertThat(supplyStockRecord.getSeqNo(), is(supplyRecord.getSeqNo() - 1)); + assertThat(supplyRecord.getSeqNo(), is(demandRecord.getSeqNo() - 1)); + assertThat(demandRecord.getSeqNo(), is(demandStockRecord.getSeqNo() - 1)); + } + + /** + * Submits two DistributionPlanEvent to the {@link MDEventListener}. + */ + @Test + public void testTwoDistibutionPlanEvents() + { + performTestTwoDistibutionPlanEvents(distributionPlanEventHandler, org); + } + + /** + * Contains the actual test for {@link #testTwoDistibutionPlanEvents()}. I moved this into a static method because i want to use the code to set the stage for other tests. + * + * @param mdEventListener + */ + public static void performTestTwoDistibutionPlanEvents( + @NonNull final DistributionPlanEventHandler distributionPlanEventHandler, + @NonNull final I_AD_Org org) + { + final TableRecordReference reference = TableRecordReference.of("someTable", 4); + + final DistributionPlanEvent event1 = DistributionPlanEvent.builder() + .eventDescr(new EventDescr()) + .distributionStart(t1) + .fromWarehouseId(fromWarehouseId) + .materialDescr(MaterialDescriptor.builder() + .date(t2) + .orgId(org.getAD_Org_ID()) + .productId(productId) + .qty(BigDecimal.TEN) + .warehouseId(intermediateWarehouseId) + .build()) + .reference(reference) + .build(); + distributionPlanEventHandler.handleDistributionPlanEvent(event1); + + assertThat(DispoTestUtils.filter(Type.SUPPLY).size(), is(1)); + assertThat(DispoTestUtils.filter(Type.DEMAND).size(), is(1)); + assertThat(DispoTestUtils.filter(Type.STOCK).size(), is(2)); // one stock record per supply/demand record + + final DistributionPlanEvent event2 = DistributionPlanEvent.builder() + .eventDescr(new EventDescr()) + .distributionStart(t2) + .fromWarehouseId(intermediateWarehouseId) + .materialDescr(MaterialDescriptor.builder() + .date(t3) + .orgId(org.getAD_Org_ID()) + .productId(productId) + .qty(BigDecimal.TEN) + .warehouseId(toWarehouseId) + .build()) + .reference(reference) + .build(); + distributionPlanEventHandler.handleDistributionPlanEvent(event2); + + assertThat(DispoTestUtils.filter(Type.SUPPLY).size(), is(2)); // one supply record per event + assertThat(DispoTestUtils.filter(Type.DEMAND).size(), is(2)); // one demand record per event + assertThat(DispoTestUtils.filter(Type.STOCK).size(), is(3)); // the supply record and the demand record with intermediateWarehouseId and t2 *share* one stock record! + + // + // we will now verify the records in their chronological (new->old) and child->parent order + assertThat(DispoTestUtils.filter(Type.STOCK, t3).size(), is(1)); + final I_MD_Candidate t3Stock = DispoTestUtils.filter(Type.STOCK, t3).get(0); + assertThat(t3Stock.getMD_Candidate_Parent_ID(), lessThanOrEqualTo(0)); + assertThat(t3Stock.getQty(), comparesEqualTo(BigDecimal.TEN)); + + assertThat(DispoTestUtils.filter(Type.SUPPLY, t3).size(), is(1)); + final I_MD_Candidate t3Supply = DispoTestUtils.filter(Type.SUPPLY, t3).get(0); + assertThat(t3Supply.getMD_Candidate_Parent_ID(), is(t3Stock.getMD_Candidate_ID())); // t3Supply => t3Stock + assertThat(t3Supply.getQty(), comparesEqualTo(BigDecimal.TEN)); + + assertThat(DispoTestUtils.filter(Type.DEMAND, t2).size(), is(1)); + final I_MD_Candidate t2Demand = DispoTestUtils.filter(Type.DEMAND, t2).get(0); + assertThat(t2Demand.getMD_Candidate_Parent_ID(), is(t3Supply.getMD_Candidate_ID())); // t2Demand => t3Supply + assertThat(t2Demand.getMD_Candidate_GroupId(), is(t3Supply.getMD_Candidate_GroupId())); // t2Demand and t3Suppy belong to the same group + assertThat(t2Demand.getQty(), comparesEqualTo(BigDecimal.TEN)); + + assertThat(DispoTestUtils.filter(Type.STOCK, t2).size(), is(1)); + final I_MD_Candidate t2Stock = DispoTestUtils.filter(Type.STOCK, t2).get(0); // this is the one that is shared! + assertThat(t2Stock.getMD_Candidate_Parent_ID(), is(t2Demand.getMD_Candidate_ID())); // t2Stock => t2Demand + assertThat(t2Stock.getQty(), comparesEqualTo(BigDecimal.ZERO)); // it's balanced between t2Demand and t2Supply + + assertThat(DispoTestUtils.filter(Type.SUPPLY, t2).size(), is(1)); + final I_MD_Candidate t2Supply = DispoTestUtils.filter(Type.SUPPLY, t2).get(0); + assertThat(t2Supply.getMD_Candidate_Parent_ID(), is(t2Stock.getMD_Candidate_ID())); // t2Supply => t2Stock + assertThat(t2Supply.getQty(), comparesEqualTo(BigDecimal.TEN)); + + assertThat(DispoTestUtils.filter(Type.DEMAND, t1).size(), is(1)); + final I_MD_Candidate t1Demand = DispoTestUtils.filter(Type.DEMAND, t1).get(0); + assertThat(t1Demand.getMD_Candidate_Parent_ID(), is(t2Supply.getMD_Candidate_ID())); // t1Demand => t2Supply + assertThat(t1Demand.getMD_Candidate_GroupId(), is(t2Supply.getMD_Candidate_GroupId())); // t2Demand and t3Suppy belong to the same group + assertThat(t1Demand.getQty(), comparesEqualTo(BigDecimal.TEN)); + + assertThat(DispoTestUtils.filter(Type.STOCK, t1).size(), is(1)); + final I_MD_Candidate t1Stock = DispoTestUtils.filter(Type.STOCK, t1).get(0); + assertThat(t1Stock.getQty(), comparesEqualTo(BigDecimal.TEN.negate())); + assertThat(t1Stock.getMD_Candidate_Parent_ID(), is(t1Demand.getMD_Candidate_ID())); + + // for display reasons we expect the MD_Candidate_IDs to have a strict order, i.e. demand - stock - supply - demand etc.. + final List allRecordSeqNos = DispoTestUtils.retrieveAllRecords().stream().map(r -> r.getSeqNo()).sorted().collect(Collectors.toList()); + assertThat(allRecordSeqNos, contains( + t3Stock.getSeqNo(), + t3Supply.getSeqNo(), + t2Demand.getSeqNo(), + t2Stock.getSeqNo(), + t2Supply.getSeqNo(), + t1Demand.getSeqNo(), + t1Stock.getSeqNo())); + } +} diff --git a/de.metas.material/dispo/src/test/java/de/metas/material/dispo/event/MDEEventListenerTests.java b/de.metas.material/dispo/src/test/java/de/metas/material/dispo/event/MDEEventListenerTests.java index d1228c382af..cee64072d95 100644 --- a/de.metas.material/dispo/src/test/java/de/metas/material/dispo/event/MDEEventListenerTests.java +++ b/de.metas.material/dispo/src/test/java/de/metas/material/dispo/event/MDEEventListenerTests.java @@ -1,23 +1,20 @@ package de.metas.material.dispo.event; +import static org.adempiere.model.InterfaceWrapperHelper.newInstance; +import static org.adempiere.model.InterfaceWrapperHelper.save; import static org.hamcrest.Matchers.comparesEqualTo; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.lessThanOrEqualTo; -import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertThat; import java.math.BigDecimal; -import java.time.Instant; import java.util.Date; import java.util.List; -import java.util.stream.Collectors; import org.adempiere.test.AdempiereTestHelper; import org.adempiere.test.AdempiereTestWatcher; import org.adempiere.util.lang.impl.TableRecordReference; import org.adempiere.util.time.SystemTime; +import org.compiere.model.I_AD_Org; import org.compiere.util.TimeUtil; import org.junit.Before; import org.junit.Rule; @@ -28,15 +25,14 @@ import de.metas.material.dispo.CandidateChangeHandler; import de.metas.material.dispo.CandidateFactory; import de.metas.material.dispo.CandidateRepository; +import de.metas.material.dispo.CandidateService; import de.metas.material.dispo.DispoTestUtils; import de.metas.material.dispo.model.I_MD_Candidate; import de.metas.material.event.DistributionPlanEvent; +import de.metas.material.event.EventDescr; import de.metas.material.event.MaterialDescriptor; import de.metas.material.event.MaterialEventService; -import de.metas.material.event.ProductionPlanEvent; import de.metas.material.event.ShipmentScheduleEvent; -import de.metas.material.event.pporder.PPOrder; -import de.metas.material.event.pporder.PPOrderLine; import mockit.Mocked; /* @@ -69,6 +65,8 @@ */ public class MDEEventListenerTests { + private static final int orderLineId = 86; + /** Watches the current tests and dumps the database to console in case of failure */ @Rule public final TestWatcher testWatcher = new AdempiereTestWatcher(); @@ -77,22 +75,16 @@ public class MDEEventListenerTests private static final Date t1 = TimeUtil.addMinutes(t0, 10); - private static final Date t2 = TimeUtil.addMinutes(t0, 20); - - private static final Date t3 = TimeUtil.addMinutes(t0, 30); - public static final int fromWarehouseId = 10; public static final int intermediateWarehouseId = 20; public static final int toWarehouseId = 30; public static final int productId = 40; - public static final int rawProduct1Id = 50; - - public static final int rawProduct2Id = 55; - private MDEventListener mdEventListener; + private I_AD_Org org; + @Mocked private MaterialEventService materialEventService; @@ -101,13 +93,20 @@ public void init() { AdempiereTestHelper.get().init(); + org = newInstance(I_AD_Org.class); + save(org); + final CandidateRepository candidateRepository = new CandidateRepository(); final SupplyProposalEvaluator supplyProposalEvaluator = new SupplyProposalEvaluator(candidateRepository); + final CandidateChangeHandler candidateChangeHandler = new CandidateChangeHandler(candidateRepository, new CandidateFactory(candidateRepository), materialEventService); + + final CandidateService candidateService = new CandidateService(candidateRepository, new MaterialEventService(de.metas.event.Type.LOCAL)); + mdEventListener = new MDEventListener( - new CandidateChangeHandler(candidateRepository, new CandidateFactory(candidateRepository), materialEventService), - candidateRepository, - supplyProposalEvaluator); + candidateChangeHandler, + new DistributionPlanEventHandler(candidateRepository, candidateChangeHandler, supplyProposalEvaluator), + new ProductionPlanEventHandler(candidateChangeHandler, candidateService)); } /** @@ -117,15 +116,16 @@ public void init() public void testShipmentScheduleEvent() { final ShipmentScheduleEvent event = ShipmentScheduleEvent.builder() + .eventDescr(new EventDescr()) .materialDescr(MaterialDescriptor.builder() .date(t1) - .orgId(20) + .orgId(org.getAD_Org_ID()) .productId(productId) .qty(BigDecimal.TEN) .warehouseId(toWarehouseId) .build()) .reference(TableRecordReference.of("someTable", 4)) - .when(Instant.now()) + .orderLineId(orderLineId) .build(); mdEventListener.onEvent(event); @@ -145,285 +145,6 @@ public void testShipmentScheduleEvent() assertThat(stockRecord.getQty(), comparesEqualTo(BigDecimal.TEN.negate())); // the stock is unbalanced, because there is no existing stock and no supply } - /** - * Verifies that for a {@link DistributionPlanEvent}, the system shall (unless the event is ignored for different reasons!) create two pairs of candidate records: - *
      - *
    • one supply-pair with a supply candidate and its stock parent
    • - *
    • one demand-pair with a demand candidate and its stock child
    • - *
    - */ - @Test - public void testSingleDistibutionPlanEvent() - { - final TableRecordReference reference = TableRecordReference.of("someTable", 4); - final DistributionPlanEvent event = DistributionPlanEvent.builder() - .distributionStart(t1) - .fromWarehouseId(fromWarehouseId) - .materialDescr(MaterialDescriptor.builder() - .date(t2) - .orgId(20) - .productId(productId) - .qty(BigDecimal.TEN) - .warehouseId(toWarehouseId) - .build()) - .reference(reference) - .when(Instant.now()) - .build(); - mdEventListener.onEvent(event); - - final List allRecords = DispoTestUtils.retrieveAllRecords(); - assertThat(allRecords.size(), is(4)); - - // all four shall have the same product - allRecords.forEach(r -> { - assertThat(r.getM_Product_ID(), is(productId)); - }); - - // all four shall have the same org - allRecords.forEach(r -> { - assertThat(r.getAD_Org_ID(), is(20)); - }); - - // all four shall have the same reference - allRecords.forEach(r -> { - final TableRecordReference ofReferenced = TableRecordReference.ofReferenced(r); - assertThat(ofReferenced, is(reference)); - }); - - assertThat(DispoTestUtils.filter(Type.SUPPLY).size(), is(1)); - assertThat(DispoTestUtils.filter(Type.STOCK).size(), is(2)); - assertThat(DispoTestUtils.filter(Type.DEMAND).size(), is(1)); - - // supplyStockRecord is the parent record of supplyRecord - final I_MD_Candidate supplyStockRecord = DispoTestUtils.filter(Type.STOCK, t2).get(0); - assertThat(supplyStockRecord.getMD_Candidate_Type(), is(Type.STOCK.toString())); - assertThat(supplyStockRecord.getMD_Candidate_Parent_ID(), lessThanOrEqualTo(0)); // supplyStockRecord shall have no parent of its own - assertThat(supplyStockRecord.getQty(), comparesEqualTo(BigDecimal.TEN)); - assertThat(supplyStockRecord.getDateProjected().getTime(), is(t2.getTime())); // shall have the same time as its supply record - assertThat(supplyStockRecord.getM_Warehouse_ID(), is(toWarehouseId)); // shall have the same wh as its supply record - - final I_MD_Candidate supplyRecord = DispoTestUtils.filter(Type.SUPPLY).get(0); - assertThat(supplyRecord.getMD_Candidate_Parent_ID(), is(supplyStockRecord.getMD_Candidate_ID())); - assertThat(supplyRecord.getDateProjected().getTime(), is(t2.getTime())); - assertThat(supplyRecord.getM_Warehouse_ID(), is(toWarehouseId)); - assertThat(supplyRecord.getQty(), comparesEqualTo(BigDecimal.TEN)); - assertThat(supplyRecord.getMD_Candidate_Parent_ID() > 0, is(true)); // supplyRecord shall have supplyStockRecord as its parent - - final I_MD_Candidate demandRecord = DispoTestUtils.filter(Type.DEMAND).get(0); - assertThat(demandRecord.getDateProjected().getTime(), is(t1.getTime())); - assertThat(demandRecord.getMD_Candidate_Parent_ID(), is(supplyRecord.getMD_Candidate_ID())); // demandRecord shall have supplyRecord as its parent - assertThat(demandRecord.getM_Warehouse_ID(), is(fromWarehouseId)); - assertThat(demandRecord.getQty(), comparesEqualTo(BigDecimal.TEN)); - - // demandStockRecord is "the other" stock record - final I_MD_Candidate demandStockRecord = DispoTestUtils.filter(Type.STOCK, t1).get(0); - assertThat(demandStockRecord.getMD_Candidate_Parent_ID(), is(demandRecord.getMD_Candidate_ID())); - assertThat(demandStockRecord.getDateProjected().getTime(), is(t1.getTime())); // demandStockRecord shall have the same time as its demand record - assertThat(demandStockRecord.getM_Warehouse_ID(), is(fromWarehouseId)); - assertThat(demandStockRecord.getQty(), comparesEqualTo(BigDecimal.TEN.negate())); - - // for display reasons we expect the MD_Candidate_IDs to have a strict order, i.e. demand - stock - supply - demand etc.. - assertThat(supplyStockRecord.getSeqNo(), is(supplyRecord.getSeqNo() - 1)); - assertThat(supplyRecord.getSeqNo(), is(demandRecord.getSeqNo() - 1)); - assertThat(demandRecord.getSeqNo(), is(demandStockRecord.getSeqNo() - 1)); - } - - /** - * Submits two DistributionPlanEvent to the {@link MDEventListener}. - */ - @Test - public void testTwoDistibutionPlanEvents() - { - performTestTwoDistibutionPlanEvents(mdEventListener); - } - - /** - * Contains the actual test for {@link #testTwoDistibutionPlanEvents()}. I moved this into a static method because i want to use the code to set the stage for other tests. - * - * @param mdEventListener - */ - public static void performTestTwoDistibutionPlanEvents(final MDEventListener mdEventListener) - { - final TableRecordReference reference = TableRecordReference.of("someTable", 4); - - final DistributionPlanEvent event1 = DistributionPlanEvent.builder() - .distributionStart(t1) - .fromWarehouseId(fromWarehouseId) - .materialDescr(MaterialDescriptor.builder() - .date(t2) - .orgId(20) - .productId(productId) - .qty(BigDecimal.TEN) - .warehouseId(intermediateWarehouseId) - .build()) - .reference(reference) - .when(Instant.now()) - .build(); - mdEventListener.onEvent(event1); - - assertThat(DispoTestUtils.filter(Type.SUPPLY).size(), is(1)); - assertThat(DispoTestUtils.filter(Type.DEMAND).size(), is(1)); - assertThat(DispoTestUtils.filter(Type.STOCK).size(), is(2)); // one stock record per supply/demand record - - final DistributionPlanEvent event2 = DistributionPlanEvent.builder() - .distributionStart(t2) - .fromWarehouseId(intermediateWarehouseId) - .materialDescr(MaterialDescriptor.builder() - .date(t3) - .orgId(20) - .productId(productId) - .qty(BigDecimal.TEN) - .warehouseId(toWarehouseId) - .build()) - .reference(reference) - .when(Instant.now()) - .build(); - mdEventListener.onEvent(event2); - - assertThat(DispoTestUtils.filter(Type.SUPPLY).size(), is(2)); // one supply record per event - assertThat(DispoTestUtils.filter(Type.DEMAND).size(), is(2)); // one demand record per event - assertThat(DispoTestUtils.filter(Type.STOCK).size(), is(3)); // the supply record and the demand record with intermediateWarehouseId and t2 *share* one stock record! - - // - // we will now verify the records in their chronological (new->old) and child->parent order - assertThat(DispoTestUtils.filter(Type.STOCK, t3).size(), is(1)); - final I_MD_Candidate t3Stock = DispoTestUtils.filter(Type.STOCK, t3).get(0); - assertThat(t3Stock.getMD_Candidate_Parent_ID(), lessThanOrEqualTo(0)); - assertThat(t3Stock.getQty(), comparesEqualTo(BigDecimal.TEN)); - - assertThat(DispoTestUtils.filter(Type.SUPPLY, t3).size(), is(1)); - final I_MD_Candidate t3Supply = DispoTestUtils.filter(Type.SUPPLY, t3).get(0); - assertThat(t3Supply.getMD_Candidate_Parent_ID(), is(t3Stock.getMD_Candidate_ID())); // t3Supply => t3Stock - assertThat(t3Supply.getQty(), comparesEqualTo(BigDecimal.TEN)); - - assertThat(DispoTestUtils.filter(Type.DEMAND, t2).size(), is(1)); - final I_MD_Candidate t2Demand = DispoTestUtils.filter(Type.DEMAND, t2).get(0); - assertThat(t2Demand.getMD_Candidate_Parent_ID(), is(t3Supply.getMD_Candidate_ID())); // t2Demand => t3Supply - assertThat(t2Demand.getMD_Candidate_GroupId(), is(t3Supply.getMD_Candidate_GroupId())); // t2Demand and t3Suppy belong to the same group - assertThat(t2Demand.getQty(), comparesEqualTo(BigDecimal.TEN)); - - assertThat(DispoTestUtils.filter(Type.STOCK, t2).size(), is(1)); - final I_MD_Candidate t2Stock = DispoTestUtils.filter(Type.STOCK, t2).get(0); // this is the one that is shared! - assertThat(t2Stock.getMD_Candidate_Parent_ID(), is(t2Demand.getMD_Candidate_ID())); // t2Stock => t2Demand - assertThat(t2Stock.getQty(), comparesEqualTo(BigDecimal.ZERO)); // it's balanced between t2Demand and t2Supply - - assertThat(DispoTestUtils.filter(Type.SUPPLY, t2).size(), is(1)); - final I_MD_Candidate t2Supply = DispoTestUtils.filter(Type.SUPPLY, t2).get(0); - assertThat(t2Supply.getMD_Candidate_Parent_ID(), is(t2Stock.getMD_Candidate_ID())); // t2Supply => t2Stock - assertThat(t2Supply.getQty(), comparesEqualTo(BigDecimal.TEN)); - - assertThat(DispoTestUtils.filter(Type.DEMAND, t1).size(), is(1)); - final I_MD_Candidate t1Demand = DispoTestUtils.filter(Type.DEMAND, t1).get(0); - assertThat(t1Demand.getMD_Candidate_Parent_ID(), is(t2Supply.getMD_Candidate_ID())); // t1Demand => t2Supply - assertThat(t1Demand.getMD_Candidate_GroupId(), is(t2Supply.getMD_Candidate_GroupId())); // t2Demand and t3Suppy belong to the same group - assertThat(t1Demand.getQty(), comparesEqualTo(BigDecimal.TEN)); - - assertThat(DispoTestUtils.filter(Type.STOCK, t1).size(), is(1)); - final I_MD_Candidate t1Stock = DispoTestUtils.filter(Type.STOCK, t1).get(0); - assertThat(t1Stock.getQty(), comparesEqualTo(BigDecimal.TEN.negate())); - assertThat(t1Stock.getMD_Candidate_Parent_ID(), is(t1Demand.getMD_Candidate_ID())); - - // for display reasons we expect the MD_Candidate_IDs to have a strict order, i.e. demand - stock - supply - demand etc.. - final List allRecordSeqNos = DispoTestUtils.retrieveAllRecords().stream().map(r -> r.getSeqNo()).sorted().collect(Collectors.toList()); - assertThat(allRecordSeqNos, contains( - t3Stock.getSeqNo(), - t3Supply.getSeqNo(), - t2Demand.getSeqNo(), - t2Stock.getSeqNo(), - t2Supply.getSeqNo(), - t1Demand.getSeqNo(), - t1Stock.getSeqNo())); - } - - @Test - public void testProductionPlanEvent() - { - final TableRecordReference reference = TableRecordReference.of("someTable", 4); - - final BigDecimal eleven = BigDecimal.TEN.add(BigDecimal.ONE); - - final ProductionPlanEvent productionPlanEvent = ProductionPlanEvent.builder() - .ppOrder(PPOrder.builder() - .orgId(20) - .datePromised(t2) - .dateStartSchedule(t1) - .productId(productId) - .quantity(BigDecimal.ONE) - .warehouseId(intermediateWarehouseId) - .plantId(120) - .uomId(130) - .productPlanningId(140) - .line(PPOrderLine.builder() - .description("descr1") - .productId(rawProduct1Id) - .qtyRequired(BigDecimal.TEN) - .productBomLineId(1020) - .receipt(false) - .build()) - .line(PPOrderLine.builder() - .description("descr2") - .productId(rawProduct2Id) - .qtyRequired(eleven) - .productBomLineId(1030) - .receipt(false) - .build()) - .build()) - .reference(reference) - .when(Instant.now()) - .build(); - - mdEventListener.onEvent(productionPlanEvent); - - assertThat(DispoTestUtils.filter(Type.SUPPLY).size(), is(1)); // - assertThat(DispoTestUtils.filter(Type.DEMAND).size(), is(2)); // we have two different inputs - assertThat(DispoTestUtils.filter(Type.STOCK).size(), is(3)); // one stock record per supply, one per demand - - final I_MD_Candidate t2Stock = DispoTestUtils.filter(Type.STOCK, t2).get(0); - assertThat(t2Stock.getQty(), comparesEqualTo(BigDecimal.ONE)); - assertThat(t2Stock.getM_Product_ID(), is(productId)); - assertThat(t2Stock.getMD_Candidate_GroupId(), greaterThan(0)); // stock candidates have their own groupIds too - assertThat(t2Stock.getMD_Candidate_Parent_ID(), lessThanOrEqualTo(0)); - - final I_MD_Candidate t2Supply = DispoTestUtils.filter(Type.SUPPLY, t2).get(0); - assertThat(t2Supply.getQty(), comparesEqualTo(BigDecimal.ONE)); - assertThat(t2Supply.getM_Product_ID(), is(productId)); - assertThat(t2Supply.getMD_Candidate_Parent_ID(), is(t2Stock.getMD_Candidate_ID())); - assertThat(t2Supply.getMD_Candidate_GroupId(), not(is(t2Stock.getMD_Candidate_GroupId()))); // stock candidates' groupIds are different from supply/demand groups' groupIds - - final int supplyDemandGroupId = t2Supply.getMD_Candidate_GroupId(); - assertThat(supplyDemandGroupId, greaterThan(0)); - - final I_MD_Candidate t1Product1Demand = DispoTestUtils.filter(Type.DEMAND, t1, rawProduct1Id).get(0); - assertThat(t1Product1Demand.getQty(), comparesEqualTo(BigDecimal.TEN)); - assertThat(t1Product1Demand.getM_Product_ID(), is(rawProduct1Id)); - assertThat(t1Product1Demand.getMD_Candidate_GroupId(), is(supplyDemandGroupId)); - // no parent relationship between production supply and demand because it can be m:n - // assertThat(t1Product1Demand.getMD_Candidate_Parent_ID(), is(t2Supply.getMD_Candidate_ID())); - - final I_MD_Candidate t1Product1Stock = DispoTestUtils.filter(Type.STOCK, t1, rawProduct1Id).get(0); - assertThat(t1Product1Stock.getQty(), comparesEqualTo(BigDecimal.TEN.negate())); - assertThat(t1Product1Stock.getM_Product_ID(), is(rawProduct1Id)); - assertThat(t1Product1Stock.getMD_Candidate_GroupId(), greaterThan(0)); // stock candidates have their own groupIds too - assertThat(t1Product1Stock.getMD_Candidate_GroupId(), not(is(supplyDemandGroupId))); // stock candidates' groupIds are different from supply/demand groups' groupIds - assertThat(t1Product1Stock.getMD_Candidate_GroupId(), not(is(t2Stock.getMD_Candidate_GroupId()))); // stock candidates' groupIds are different if they are about different products or warehouses - - assertThat(t1Product1Stock.getMD_Candidate_Parent_ID(), is(t1Product1Demand.getMD_Candidate_ID())); - - final I_MD_Candidate t1Product2Demand = DispoTestUtils.filter(Type.DEMAND, t1, rawProduct2Id).get(0); - assertThat(t1Product2Demand.getQty(), comparesEqualTo(eleven)); - assertThat(t1Product2Demand.getM_Product_ID(), is(rawProduct2Id)); - assertThat(t1Product2Demand.getMD_Candidate_GroupId(), is(supplyDemandGroupId)); - // no parent relationship between production supply and demand because it can be m:n - // assertThat(t1Product2Demand.getMD_Candidate_Parent_ID(), is(t2Supply.getMD_Candidate_ID())); - - final I_MD_Candidate t1Product2Stock = DispoTestUtils.filter(Type.STOCK, t1, rawProduct2Id).get(0); - assertThat(t1Product2Stock.getQty(), comparesEqualTo(eleven.negate())); - assertThat(t1Product2Stock.getM_Product_ID(), is(rawProduct2Id)); - assertThat(t1Product2Stock.getMD_Candidate_GroupId(), greaterThan(0)); // stock candidates have their own groupIds too - assertThat(t1Product2Stock.getMD_Candidate_Parent_ID(), is(t1Product2Demand.getMD_Candidate_ID())); - assertThat(t1Product2Stock.getMD_Candidate_GroupId(), not(is(t1Product1Stock.getMD_Candidate_GroupId()))); // stock candidates' groupIds are different if they are about different products or warehouses - } - /** * This test is more for myself, to figure out how the system works :-$ */ @@ -435,17 +156,17 @@ public void testShipmentScheduleEven_then_DistributionPlanevent() // create a DistributionPlanEvent event which matches the shipmentscheduleEvent that we processed in testShipmentScheduleEvent() final TableRecordReference reference = TableRecordReference.of("someTable", 4); final DistributionPlanEvent event = DistributionPlanEvent.builder() + .eventDescr(new EventDescr()) .distributionStart(t1) .fromWarehouseId(fromWarehouseId) .materialDescr(MaterialDescriptor.builder() .date(t1) - .orgId(20) + .orgId(org.getAD_Org_ID()) .productId(productId) .qty(BigDecimal.TEN) .warehouseId(toWarehouseId) .build()) .reference(reference) - .when(Instant.now()) .build(); mdEventListener.onEvent(event); diff --git a/de.metas.material/dispo/src/test/java/de/metas/material/dispo/event/ProdcutionPlanEventHandlerTests.java b/de.metas.material/dispo/src/test/java/de/metas/material/dispo/event/ProdcutionPlanEventHandlerTests.java new file mode 100644 index 00000000000..0ad396589bd --- /dev/null +++ b/de.metas.material/dispo/src/test/java/de/metas/material/dispo/event/ProdcutionPlanEventHandlerTests.java @@ -0,0 +1,206 @@ +package de.metas.material.dispo.event; + +import static org.adempiere.model.InterfaceWrapperHelper.newInstance; +import static org.adempiere.model.InterfaceWrapperHelper.save; +import static org.hamcrest.Matchers.comparesEqualTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.lessThanOrEqualTo; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertThat; + +import java.math.BigDecimal; +import java.util.Date; + +import org.adempiere.test.AdempiereTestHelper; +import org.adempiere.util.lang.impl.TableRecordReference; +import org.adempiere.util.time.SystemTime; +import org.compiere.model.I_AD_Org; +import org.compiere.util.TimeUtil; +import org.junit.Before; +import org.junit.Test; + +import de.metas.material.dispo.Candidate.Type; +import de.metas.material.dispo.CandidateChangeHandler; +import de.metas.material.dispo.CandidateFactory; +import de.metas.material.dispo.CandidateRepository; +import de.metas.material.dispo.CandidateService; +import de.metas.material.dispo.DispoTestUtils; +import de.metas.material.dispo.model.I_MD_Candidate; +import de.metas.material.event.EventDescr; +import de.metas.material.event.MaterialEventService; +import de.metas.material.event.ProductionPlanEvent; +import de.metas.material.event.pporder.PPOrder; +import de.metas.material.event.pporder.PPOrderLine; +import mockit.Mocked; + +/* + * #%L + * metasfresh-material-dispo + * %% + * Copyright (C) 2017 metas GmbH + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +public class ProdcutionPlanEventHandlerTests +{ + public static final Date t0 = SystemTime.asDate(); + + private static final Date t1 = TimeUtil.addMinutes(t0, 10); + + private static final Date t2 = TimeUtil.addMinutes(t0, 20); + + public static final int rawProduct1Id = 50; + + public static final int rawProduct2Id = 55; + + public static final int productId = 40; + + public static final int intermediateWarehouseId = 20; + + private TableRecordReference reference; + + private final BigDecimal eleven = BigDecimal.TEN.add(BigDecimal.ONE); + + private I_AD_Org org; + + @Mocked + private MaterialEventService materialEventService; + + private ProductionPlanEventHandler productionPlanEventHandler; + + @Before + public void init() + { + AdempiereTestHelper.get().init(); + + reference = TableRecordReference.of("someTable", 4); + + org = newInstance(I_AD_Org.class); + save(org); + + final CandidateRepository candidateRepository = new CandidateRepository(); + final CandidateChangeHandler candidateChangeHandler = new CandidateChangeHandler(candidateRepository, new CandidateFactory(candidateRepository), materialEventService); + final CandidateService candidateService = new CandidateService(candidateRepository, new MaterialEventService(de.metas.event.Type.LOCAL)); + + productionPlanEventHandler = new ProductionPlanEventHandler(candidateChangeHandler, candidateService); + } + + @Test + public void testProductionPlanEvent() + { + final ProductionPlanEvent productionPlanEvent = createProductionPlanEvent(); + perform_testProductionPlanEvent(productionPlanEvent); + } + + @Test + public void testProductionPlanEvent_invoke_twice() + { + final ProductionPlanEvent productionPlanEvent = createProductionPlanEvent(); + perform_testProductionPlanEvent(productionPlanEvent); + perform_testProductionPlanEvent(productionPlanEvent); + } + + private void perform_testProductionPlanEvent(final ProductionPlanEvent productionPlanEvent) + { + productionPlanEventHandler.handleProductionPlanEvent(productionPlanEvent); + + assertThat(DispoTestUtils.filter(Type.SUPPLY).size(), is(1)); // + assertThat(DispoTestUtils.filter(Type.DEMAND).size(), is(2)); // we have two different inputs + assertThat(DispoTestUtils.filter(Type.STOCK).size(), is(3)); // one stock record per supply, one per demand + + final I_MD_Candidate t2Stock = DispoTestUtils.filter(Type.STOCK, t2).get(0); + assertThat(t2Stock.getQty(), comparesEqualTo(BigDecimal.ONE)); + assertThat(t2Stock.getM_Product_ID(), is(productId)); + assertThat(t2Stock.getMD_Candidate_GroupId(), greaterThan(0)); // stock candidates have their own groupIds too + assertThat(t2Stock.getMD_Candidate_Parent_ID(), lessThanOrEqualTo(0)); + + final I_MD_Candidate t2Supply = DispoTestUtils.filter(Type.SUPPLY, t2).get(0); + assertThat(t2Supply.getQty(), comparesEqualTo(BigDecimal.ONE)); + assertThat(t2Supply.getM_Product_ID(), is(productId)); + assertThat(t2Supply.getMD_Candidate_Parent_ID(), is(t2Stock.getMD_Candidate_ID())); + assertThat(t2Supply.getMD_Candidate_GroupId(), not(is(t2Stock.getMD_Candidate_GroupId()))); // stock candidates' groupIds are different from supply/demand groups' groupIds + + final int supplyDemandGroupId = t2Supply.getMD_Candidate_GroupId(); + assertThat(supplyDemandGroupId, greaterThan(0)); + + final I_MD_Candidate t1Product1Demand = DispoTestUtils.filter(Type.DEMAND, t1, rawProduct1Id).get(0); + assertThat(t1Product1Demand.getQty(), comparesEqualTo(BigDecimal.TEN)); + assertThat(t1Product1Demand.getM_Product_ID(), is(rawProduct1Id)); + assertThat(t1Product1Demand.getMD_Candidate_GroupId(), is(supplyDemandGroupId)); + // no parent relationship between production supply and demand because it can be m:n + // assertThat(t1Product1Demand.getMD_Candidate_Parent_ID(), is(t2Supply.getMD_Candidate_ID())); + + final I_MD_Candidate t1Product1Stock = DispoTestUtils.filter(Type.STOCK, t1, rawProduct1Id).get(0); + assertThat(t1Product1Stock.getQty(), comparesEqualTo(BigDecimal.TEN.negate())); + assertThat(t1Product1Stock.getM_Product_ID(), is(rawProduct1Id)); + assertThat(t1Product1Stock.getMD_Candidate_GroupId(), greaterThan(0)); // stock candidates have their own groupIds too + assertThat(t1Product1Stock.getMD_Candidate_GroupId(), not(is(supplyDemandGroupId))); // stock candidates' groupIds are different from supply/demand groups' groupIds + assertThat(t1Product1Stock.getMD_Candidate_GroupId(), not(is(t2Stock.getMD_Candidate_GroupId()))); // stock candidates' groupIds are different if they are about different products or warehouses + + assertThat(t1Product1Stock.getMD_Candidate_Parent_ID(), is(t1Product1Demand.getMD_Candidate_ID())); + + final I_MD_Candidate t1Product2Demand = DispoTestUtils.filter(Type.DEMAND, t1, rawProduct2Id).get(0); + assertThat(t1Product2Demand.getQty(), comparesEqualTo(eleven)); + assertThat(t1Product2Demand.getM_Product_ID(), is(rawProduct2Id)); + assertThat(t1Product2Demand.getMD_Candidate_GroupId(), is(supplyDemandGroupId)); + // no parent relationship between production supply and demand because it can be m:n + // assertThat(t1Product2Demand.getMD_Candidate_Parent_ID(), is(t2Supply.getMD_Candidate_ID())); + + final I_MD_Candidate t1Product2Stock = DispoTestUtils.filter(Type.STOCK, t1, rawProduct2Id).get(0); + assertThat(t1Product2Stock.getQty(), comparesEqualTo(eleven.negate())); + assertThat(t1Product2Stock.getM_Product_ID(), is(rawProduct2Id)); + assertThat(t1Product2Stock.getMD_Candidate_GroupId(), greaterThan(0)); // stock candidates have their own groupIds too + assertThat(t1Product2Stock.getMD_Candidate_Parent_ID(), is(t1Product2Demand.getMD_Candidate_ID())); + assertThat(t1Product2Stock.getMD_Candidate_GroupId(), not(is(t1Product1Stock.getMD_Candidate_GroupId()))); // stock candidates' groupIds are different if they are about different products or warehouses + } + + private ProductionPlanEvent createProductionPlanEvent() + { + final ProductionPlanEvent productionPlanEvent = ProductionPlanEvent.builder() + .eventDescr(new EventDescr()) + .ppOrder(PPOrder.builder() + .orgId(org.getAD_Org_ID()) + .datePromised(t2) + .dateStartSchedule(t1) + .productId(productId) + .quantity(BigDecimal.ONE) + .warehouseId(intermediateWarehouseId) + .plantId(120) + .uomId(130) + .productPlanningId(140) + .line(PPOrderLine.builder() + .description("descr1") + .productId(rawProduct1Id) + .qtyRequired(BigDecimal.TEN) + .productBomLineId(1020) + .receipt(false) + .build()) + .line(PPOrderLine.builder() + .description("descr2") + .productId(rawProduct2Id) + .qtyRequired(eleven) + .productBomLineId(1030) + .receipt(false) + .build()) + .build()) + .reference(reference) + .build(); + return productionPlanEvent; + } + +} diff --git a/de.metas.material/dispo/src/test/java/de/metas/material/dispo/event/SupplyProposalEvaluatorTests.java b/de.metas.material/dispo/src/test/java/de/metas/material/dispo/event/SupplyProposalEvaluatorTests.java index 2671f3ae9f7..d16500aa38c 100644 --- a/de.metas.material/dispo/src/test/java/de/metas/material/dispo/event/SupplyProposalEvaluatorTests.java +++ b/de.metas.material/dispo/src/test/java/de/metas/material/dispo/event/SupplyProposalEvaluatorTests.java @@ -1,5 +1,7 @@ package de.metas.material.dispo.event; +import static org.adempiere.model.InterfaceWrapperHelper.newInstance; +import static org.adempiere.model.InterfaceWrapperHelper.save; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; @@ -9,6 +11,7 @@ import org.adempiere.test.AdempiereTestHelper; import org.adempiere.test.AdempiereTestWatcher; import org.adempiere.util.time.SystemTime; +import org.compiere.model.I_AD_Org; import org.compiere.util.TimeUtil; import org.junit.Before; import org.junit.Rule; @@ -62,7 +65,9 @@ public class SupplyProposalEvaluatorTests private static final int DEMAND_WAREHOUSE_ID = 6; - private MDEventListener mdEventListener; + //private MDEventListener mdEventListener; + + private DistributionPlanEventHandler distributionPlanEventHandler; /** * This is the code under test @@ -75,18 +80,22 @@ public class SupplyProposalEvaluatorTests @Mocked private MaterialEventService materialEventService; + private I_AD_Org org; + @Before public void init() { AdempiereTestHelper.get().init(); + org = newInstance(I_AD_Org.class); + save(org); + candidateRepository = new CandidateRepository(); supplyProposalEvaluator = new SupplyProposalEvaluator(candidateRepository); - mdEventListener = new MDEventListener( - new CandidateChangeHandler(candidateRepository, new CandidateFactory(candidateRepository), materialEventService), - candidateRepository, - supplyProposalEvaluator); + final CandidateChangeHandler candidateChangeHandler = new CandidateChangeHandler(candidateRepository, new CandidateFactory(candidateRepository), materialEventService); + + distributionPlanEventHandler = new DistributionPlanEventHandler(candidateRepository, candidateChangeHandler, supplyProposalEvaluator); } /** @@ -167,7 +176,7 @@ public void testWithOppositeDirectionData() private void addSimpleSupplyDemand() { final Candidate supplyCandidate = Candidate.builder() - .orgId(1) + .orgId(org.getAD_Org_ID()) .date(t3) .productId(3) .quantity(BigDecimal.TEN) @@ -175,10 +184,10 @@ private void addSimpleSupplyDemand() .warehouseId(SUPPLY_WAREHOUSE_ID) .build(); - final Candidate supplyCandidateWithId = candidateRepository.addOrReplace(supplyCandidate); + final Candidate supplyCandidateWithId = candidateRepository.addOrUpdate(supplyCandidate); final Candidate demandCandidate = Candidate.builder() - .orgId(1) + .orgId(org.getAD_Org_ID()) .date(t2) .parentId(supplyCandidateWithId.getId()) .productId(3) @@ -187,7 +196,7 @@ private void addSimpleSupplyDemand() .warehouseId(DEMAND_WAREHOUSE_ID) .build(); - candidateRepository.addOrReplace(demandCandidate); + candidateRepository.addOrUpdate(demandCandidate); } /** @@ -196,7 +205,7 @@ private void addSimpleSupplyDemand() @Test public void testWithChain() { - MDEEventListenerTests.performTestTwoDistibutionPlanEvents(mdEventListener); + DistributionPlanEventHandlerTests.performTestTwoDistibutionPlanEvents(distributionPlanEventHandler, org); // propose what would create an additional demand on A and an additional supply on B. nothing wrong with that final SupplyProposal supplyProposal1 = SupplyProposal.builder() @@ -232,7 +241,7 @@ public void testWithChain() @Test public void testWithChainOpposite() { - MDEEventListenerTests.performTestTwoDistibutionPlanEvents(mdEventListener); + DistributionPlanEventHandlerTests.performTestTwoDistibutionPlanEvents(distributionPlanEventHandler, org); // we now have an unbalanced demand with a stock of -10 in "fromWarehouseId" (because that's where the "last" demand of the "last" DistibutionPlan is) // and we have a stock of +10 in "toWarehouseId" diff --git a/de.metas.material/event/src/main/java/de/metas/material/event/DistributionPlanEvent.java b/de.metas.material/event/src/main/java/de/metas/material/event/DistributionPlanEvent.java index 6ed79847869..e55bf2c58cf 100644 --- a/de.metas.material/event/src/main/java/de/metas/material/event/DistributionPlanEvent.java +++ b/de.metas.material/event/src/main/java/de/metas/material/event/DistributionPlanEvent.java @@ -1,6 +1,5 @@ package de.metas.material.event; -import java.time.Instant; import java.util.Date; import org.adempiere.util.lang.impl.TableRecordReference; @@ -34,7 +33,7 @@ */ /** * Send by the material planner when it came up with a distribution plan that could be turned into an {@link I_DD_Order}. - * + * * @author metas-dev */ @Data @@ -45,9 +44,8 @@ public class DistributionPlanEvent implements MaterialEvent public static final String TYPE = "DistributionPlanEvent"; @NonNull - private final Instant when; + private final EventDescr eventDescr; - @NonNull private final TableRecordReference reference; @NonNull @@ -59,4 +57,6 @@ public class DistributionPlanEvent implements MaterialEvent @NonNull private final MaterialDescriptor materialDescr; + private int orderLineId; + } diff --git a/de.metas.material/event/src/main/java/de/metas/material/event/EventDescr.java b/de.metas.material/event/src/main/java/de/metas/material/event/EventDescr.java new file mode 100644 index 00000000000..0e7b9fdc298 --- /dev/null +++ b/de.metas.material/event/src/main/java/de/metas/material/event/EventDescr.java @@ -0,0 +1,46 @@ +package de.metas.material.event; + +import java.time.Instant; +import java.util.UUID; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NonNull; + +/* + * #%L + * metasfresh-material-event + * %% + * Copyright (C) 2017 metas GmbH + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +@Data +@AllArgsConstructor +public class EventDescr +{ + + public EventDescr() + { + this(Instant.now(), UUID.randomUUID()); + } + + @NonNull + private final Instant when; + + @NonNull + private final UUID uuid; +} diff --git a/de.metas.material/event/src/main/java/de/metas/material/event/MaterialDemandEvent.java b/de.metas.material/event/src/main/java/de/metas/material/event/MaterialDemandEvent.java index 25e3d0dc893..07e720db29b 100644 --- a/de.metas.material/event/src/main/java/de/metas/material/event/MaterialDemandEvent.java +++ b/de.metas.material/event/src/main/java/de/metas/material/event/MaterialDemandEvent.java @@ -37,8 +37,12 @@ public class MaterialDemandEvent implements MaterialEvent public static final String TYPE = "MaterialDemandEvent"; @NonNull - private final MaterialDescriptor descr; + private final EventDescr eventDescr; @NonNull + private final MaterialDescriptor descr; + private final TableRecordReference reference; + + private int orderLineId; } diff --git a/de.metas.material/event/src/main/java/de/metas/material/event/MaterialEvent.java b/de.metas.material/event/src/main/java/de/metas/material/event/MaterialEvent.java index 0a2d68e9510..f15fc8af5d9 100644 --- a/de.metas.material/event/src/main/java/de/metas/material/event/MaterialEvent.java +++ b/de.metas.material/event/src/main/java/de/metas/material/event/MaterialEvent.java @@ -39,11 +39,12 @@ @JsonSubTypes.Type(name = MaterialDemandEvent.TYPE, value = MaterialDemandEvent.class), @JsonSubTypes.Type(name = DistributionPlanEvent.TYPE, value = DistributionPlanEvent.class), @JsonSubTypes.Type(name = ProductionPlanEvent.TYPE, value = ProductionPlanEvent.class), - @JsonSubTypes.Type(name = ProductionOrderRequested.TYPE, value = ProductionOrderRequested.class), + @JsonSubTypes.Type(name = PPOrderRequestedEvent.TYPE, value = PPOrderRequestedEvent.class), @JsonSubTypes.Type(name = ReceiptScheduleEvent.TYPE, value = ReceiptScheduleEvent.class), @JsonSubTypes.Type(name = ShipmentScheduleEvent.TYPE, value = ShipmentScheduleEvent.class), @JsonSubTypes.Type(name = TransactionEvent.TYPE, value = TransactionEvent.class) }) public interface MaterialEvent { + EventDescr getEventDescr(); } diff --git a/de.metas.material/event/src/main/java/de/metas/material/event/MaterialEventConfiguration.java b/de.metas.material/event/src/main/java/de/metas/material/event/MaterialEventConfiguration.java index 362c24854eb..0a689aed6d4 100644 --- a/de.metas.material/event/src/main/java/de/metas/material/event/MaterialEventConfiguration.java +++ b/de.metas.material/event/src/main/java/de/metas/material/event/MaterialEventConfiguration.java @@ -6,7 +6,6 @@ import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Profile; -import de.metas.StartupListener; import de.metas.event.Type; /* @@ -34,7 +33,8 @@ @Configuration @ComponentScan(basePackageClasses = { MaterialEventConfiguration.class, - StartupListener.class }) + // StartupListener.class // there are different startup listener classes. one for metasfresh-backend, one for metasfresh-webui-api. +}) public class MaterialEventConfiguration { diff --git a/de.metas.material/event/src/main/java/de/metas/material/event/MaterialEventService.java b/de.metas.material/event/src/main/java/de/metas/material/event/MaterialEventService.java index 562f89afa13..cebb5ad21ca 100644 --- a/de.metas.material/event/src/main/java/de/metas/material/event/MaterialEventService.java +++ b/de.metas.material/event/src/main/java/de/metas/material/event/MaterialEventService.java @@ -4,6 +4,7 @@ import java.util.List; import org.adempiere.ad.trx.api.ITrxManager; +import org.adempiere.service.ISysConfigBL; import org.adempiere.util.Services; import org.springframework.stereotype.Service; @@ -50,6 +51,8 @@ public class MaterialEventService /** Topic used to send notifications about sales and purchase orders that were generated/reversed asynchronously */ private final Topic eventBusTopic; + private boolean subscribedToEventBus = false; + private final IEventListener internalListener = new IEventListener() { @Override @@ -75,16 +78,43 @@ public MaterialEventService(@NonNull final Type eventType) .setName(MaterialEventBus.EVENTBUS_TOPIC_NAME) .setType(eventType) .build(); + } + /** + * With a "non-local" eventService, we can't directly get the event-bus on startup, because at that time, metasfresh is not yet ready. + * More concretely, the problem is that the registerListener method will invoke {@link ISysConfigBL} which will try an look into the DB. + *

    + * Therefore, we have this particular method to be called whenever we know that it's now safe to call it. In old-school scenarios, that is probably a model validator. + * Note that this method can be called often, but only the first call makes a difference. + */ + public synchronized void subscribeToEventBus() + { + if(subscribedToEventBus) + { + return; // nothing to do + } getEventBus().subscribe(internalListener); + subscribedToEventBus = true; } - public void registerListener(final MaterialEventListener materialDemandListener) + /** + * Register the given {@code listener} to this service. + * This can be done before {@link #subscribeToEventBus()} was called, but the registered listener then won't yet be invoked by the framework. + * + * @param materialDemandListener + */ + public void registerListener(final MaterialEventListener listener) { - Preconditions.checkNotNull(materialDemandListener, "Param materialDemandListener is null"); - listeners.add(materialDemandListener); + Preconditions.checkNotNull(listener, "Param listener is null"); + listeners.add(listener); } + /** + * Adds a trx listener to make sure the given {@code event} will be fired via {@link #fireEvent(MaterialEvent)} when the given {@code trxName} is committed. + * + * @param event + * @param trxName + */ public void fireEventAfterCommit(final MaterialEvent event, final String trxName) { final ITrxManager trxManager = Services.get(ITrxManager.class); @@ -94,8 +124,15 @@ public void fireEventAfterCommit(final MaterialEvent event, final String trxName .onAfterCommit(() -> fireEvent(event)); } + /** + * Fires the given event using our (distributed) event framework. If {@link #subscribeToEventBus()} was not yet invoked, an exception is thorwn. + * + * @param event + */ public void fireEvent(final MaterialEvent event) { + Preconditions.checkState(subscribedToEventBus, "The method subscribeToEventBus() was no yet called on this instance; this=%s", this); + final String eventStr = MaterialEventSerializer.get().serialize(event); final Event realEvent = Event.builder() @@ -112,5 +149,4 @@ private IEventBus getEventBus() final IEventBus eventBus = eventBusFactory.getEventBus(eventBusTopic); return eventBus; } - } diff --git a/de.metas.material/event/src/main/java/de/metas/material/event/ProductionOrderRequested.java b/de.metas.material/event/src/main/java/de/metas/material/event/PPOrderRequestedEvent.java similarity index 92% rename from de.metas.material/event/src/main/java/de/metas/material/event/ProductionOrderRequested.java rename to de.metas.material/event/src/main/java/de/metas/material/event/PPOrderRequestedEvent.java index b3b60acd1bd..b2d1feb3e72 100644 --- a/de.metas.material/event/src/main/java/de/metas/material/event/ProductionOrderRequested.java +++ b/de.metas.material/event/src/main/java/de/metas/material/event/PPOrderRequestedEvent.java @@ -1,7 +1,5 @@ package de.metas.material.event; -import java.time.Instant; - import org.adempiere.util.lang.impl.TableRecordReference; import org.eevolution.model.I_PP_Order; @@ -38,21 +36,20 @@ *

    * Important: right now, any {@link PPOrderLine}s are ignored. The receiver of this event will mostly use * the event's {@link PPOrder}'s {@link PPOrder#getProductPlanningId()} to create the @{code PP_Order}. - * + * * @author metas-dev * */ @Data @AllArgsConstructor @Builder -public class ProductionOrderRequested implements MaterialEvent +public class PPOrderRequestedEvent implements MaterialEvent { public static final String TYPE = "ProductionOrderEvent"; @NonNull - private final Instant when; + private final EventDescr eventDescr; - @NonNull private final TableRecordReference reference; @NonNull diff --git a/de.metas.material/event/src/main/java/de/metas/material/event/ProductionPlanEvent.java b/de.metas.material/event/src/main/java/de/metas/material/event/ProductionPlanEvent.java index 400ecd7fbab..a94c6ba5668 100644 --- a/de.metas.material/event/src/main/java/de/metas/material/event/ProductionPlanEvent.java +++ b/de.metas.material/event/src/main/java/de/metas/material/event/ProductionPlanEvent.java @@ -1,7 +1,5 @@ package de.metas.material.event; -import java.time.Instant; - import org.adempiere.util.lang.impl.TableRecordReference; import org.eevolution.model.I_PP_Order; @@ -46,7 +44,7 @@ final public class ProductionPlanEvent implements MaterialEvent public static final String TYPE = "ProductionPlanEvent"; @NonNull - private final Instant when; + private final EventDescr eventDescr; private final TableRecordReference reference; diff --git a/de.metas.material/event/src/main/java/de/metas/material/event/ReceiptScheduleEvent.java b/de.metas.material/event/src/main/java/de/metas/material/event/ReceiptScheduleEvent.java index 837f09cd053..f25812cd484 100644 --- a/de.metas.material/event/src/main/java/de/metas/material/event/ReceiptScheduleEvent.java +++ b/de.metas.material/event/src/main/java/de/metas/material/event/ReceiptScheduleEvent.java @@ -1,7 +1,5 @@ package de.metas.material.event; -import java.time.Instant; - import org.adempiere.util.lang.impl.TableRecordReference; import lombok.AllArgsConstructor; @@ -38,7 +36,7 @@ public class ReceiptScheduleEvent implements MaterialEvent public static final String TYPE = "ReceiptScheduleEvent"; @NonNull - private final Instant when; + private final EventDescr eventDescr; @NonNull private final TableRecordReference reference; diff --git a/de.metas.material/event/src/main/java/de/metas/material/event/ShipmentScheduleEvent.java b/de.metas.material/event/src/main/java/de/metas/material/event/ShipmentScheduleEvent.java index 2fe56d4dc98..ef64a41a134 100644 --- a/de.metas.material/event/src/main/java/de/metas/material/event/ShipmentScheduleEvent.java +++ b/de.metas.material/event/src/main/java/de/metas/material/event/ShipmentScheduleEvent.java @@ -1,7 +1,5 @@ package de.metas.material.event; -import java.time.Instant; - import org.adempiere.util.lang.impl.TableRecordReference; import lombok.AllArgsConstructor; @@ -38,7 +36,7 @@ public class ShipmentScheduleEvent implements MaterialEvent public static final String TYPE = "ShipmentScheduleEvent"; @NonNull - private final Instant when; + private final EventDescr eventDescr; @NonNull private final TableRecordReference reference; @@ -50,4 +48,6 @@ public class ShipmentScheduleEvent implements MaterialEvent * Note that we count an inactive shipment schedule as deleted too, because as far as the material dispo is concerned, there is no difference */ private final boolean shipmentScheduleDeleted; + + private final int orderLineId; } diff --git a/de.metas.material/event/src/main/java/de/metas/material/event/TransactionEvent.java b/de.metas.material/event/src/main/java/de/metas/material/event/TransactionEvent.java index 71da7b8a58d..6922160915a 100644 --- a/de.metas.material/event/src/main/java/de/metas/material/event/TransactionEvent.java +++ b/de.metas.material/event/src/main/java/de/metas/material/event/TransactionEvent.java @@ -1,7 +1,5 @@ package de.metas.material.event; -import java.time.Instant; - import org.adempiere.util.lang.impl.TableRecordReference; import lombok.AllArgsConstructor; @@ -38,7 +36,7 @@ public class TransactionEvent implements MaterialEvent public static final String TYPE = "TransactionEvent"; @NonNull - private Instant when; + private final EventDescr eventDescr; @NonNull private final TableRecordReference reference; diff --git a/de.metas.material/event/src/main/java/de/metas/material/event/pporder/PPOrder.java b/de.metas.material/event/src/main/java/de/metas/material/event/pporder/PPOrder.java index cb5e0dcfed9..05e40245134 100644 --- a/de.metas.material/event/src/main/java/de/metas/material/event/pporder/PPOrder.java +++ b/de.metas.material/event/src/main/java/de/metas/material/event/pporder/PPOrder.java @@ -88,6 +88,11 @@ public class PPOrder @NonNull private final BigDecimal quantity; + /** + * If {@code true}, then this event advises the recipient to directly request an actual PP_Order to be created. + */ + private final boolean createPPOrder; + /** * Attention, might be {@code null}. */ diff --git a/de.metas.material/event/src/test/java/de/metas/material/event/impl/ManufactoringEventSerializerTests.java b/de.metas.material/event/src/test/java/de/metas/material/event/impl/ManufactoringEventSerializerTests.java index 207cbffcafb..612ad845d89 100644 --- a/de.metas.material/event/src/test/java/de/metas/material/event/impl/ManufactoringEventSerializerTests.java +++ b/de.metas.material/event/src/test/java/de/metas/material/event/impl/ManufactoringEventSerializerTests.java @@ -5,7 +5,6 @@ import static org.junit.Assert.assertThat; import java.math.BigDecimal; -import java.time.Instant; import org.adempiere.model.InterfaceWrapperHelper; import org.adempiere.test.AdempiereTestHelper; @@ -15,9 +14,10 @@ import org.junit.Before; import org.junit.Test; +import de.metas.material.event.EventDescr; import de.metas.material.event.MaterialDescriptor; import de.metas.material.event.MaterialEvent; -import de.metas.material.event.ProductionOrderRequested; +import de.metas.material.event.PPOrderRequestedEvent; import de.metas.material.event.ProductionPlanEvent; import de.metas.material.event.ReceiptScheduleEvent; import de.metas.material.event.TransactionEvent; @@ -62,6 +62,7 @@ public void testReceiptScheduleEvent() InterfaceWrapperHelper.save(someOtherTable); final ReceiptScheduleEvent evt = ReceiptScheduleEvent.builder() + .eventDescr(new EventDescr()) .materialDescr(MaterialDescriptor.builder() .date(SystemTime.asDate()) .orgId(10) @@ -72,7 +73,6 @@ public void testReceiptScheduleEvent() .build()) .receiptScheduleDeleted(false) .reference(TableRecordReference.of("someOtherTable", 100)) - .when(Instant.now()) .build(); assertThat(evt.getMaterialDescr().getQty(), comparesEqualTo(BigDecimal.TEN)); // guard @@ -106,6 +106,7 @@ public static TransactionEvent createSampleTransactionEvent() final TransactionEvent evt = TransactionEvent .builder() + .eventDescr(new EventDescr()) .materialDescr(MaterialDescriptor.builder() .productId(14) .qty(BigDecimal.TEN) @@ -114,7 +115,6 @@ public static TransactionEvent createSampleTransactionEvent() .orgId(66) .build()) .reference(TableRecordReference.of(1, 2)) - .when(Instant.now()) .build(); return evt; } @@ -122,8 +122,8 @@ public static TransactionEvent createSampleTransactionEvent() @Test public void testProductionOrderEvent() { - final ProductionOrderRequested event = ProductionOrderRequested.builder() - .when(Instant.now()) + final PPOrderRequestedEvent event = PPOrderRequestedEvent.builder() + .eventDescr(new EventDescr()) .reference(TableRecordReference.of("table", 24)) .ppOrder(PPOrder.builder() .datePromised(SystemTime.asDate()) @@ -158,15 +158,15 @@ public void testProductionOrderEvent() final String serializedEvt = MaterialEventSerializer.get().serialize(event); final MaterialEvent deserializedEvt = MaterialEventSerializer.get().deserialize(serializedEvt); - + assertThat(deserializedEvt, is(event)); } - + @Test public void testProductionPlanEvent() { final ProductionPlanEvent event = ProductionPlanEvent.builder() - .when(Instant.now()) + .eventDescr(new EventDescr()) .reference(TableRecordReference.of("table", 24)) .ppOrder(PPOrder.builder() .datePromised(SystemTime.asDate()) @@ -201,7 +201,7 @@ public void testProductionPlanEvent() final String serializedEvt = MaterialEventSerializer.get().serialize(event); final MaterialEvent deserializedEvt = MaterialEventSerializer.get().deserialize(serializedEvt); - + assertThat(deserializedEvt, is(event)); } } diff --git a/de.metas.material/dispo/manufacturing-dispo.launch b/de.metas.material/material-dispo.launch similarity index 86% rename from de.metas.material/dispo/manufacturing-dispo.launch rename to de.metas.material/material-dispo.launch index f1e7e1fa640..20b16a1943c 100644 --- a/de.metas.material/dispo/manufacturing-dispo.launch +++ b/de.metas.material/material-dispo.launch @@ -10,5 +10,5 @@ - + diff --git a/de.metas.material/planning/src/main/java/de/metas/material/planning/event/MaterialDemandListener.java b/de.metas.material/planning/src/main/java/de/metas/material/planning/event/MaterialDemandListener.java index f4ade0a6727..a173ba06288 100644 --- a/de.metas.material/planning/src/main/java/de/metas/material/planning/event/MaterialDemandListener.java +++ b/de.metas.material/planning/src/main/java/de/metas/material/planning/event/MaterialDemandListener.java @@ -2,7 +2,6 @@ import java.math.BigDecimal; import java.sql.Timestamp; -import java.time.Instant; import java.util.Collections; import java.util.Date; import java.util.List; @@ -26,6 +25,7 @@ import de.metas.logging.LogManager; import de.metas.material.event.DistributionPlanEvent; +import de.metas.material.event.EventDescr; import de.metas.material.event.MaterialDemandEvent; import de.metas.material.event.MaterialDescriptor; import de.metas.material.event.MaterialEvent; @@ -48,6 +48,7 @@ import de.metas.material.planning.pporder.PPOrderDemandMatcher; import de.metas.material.planning.pporder.PPOrderPojoConverter; import de.metas.material.planning.pporder.PPOrderPojoSupplier; +import lombok.NonNull; /* * #%L @@ -102,7 +103,7 @@ public class MaterialDemandListener implements MaterialEventListener @Override - public void onEvent(final MaterialEvent event) + public void onEvent(@NonNull final MaterialEvent event) { if (!(event instanceof MaterialDemandEvent)) { @@ -113,7 +114,7 @@ public void onEvent(final MaterialEvent event) handleMaterialDemandEvent((MaterialDemandEvent)event); } - private void handleMaterialDemandEvent(final MaterialDemandEvent materialDemandEvent) + private void handleMaterialDemandEvent(@NonNull final MaterialDemandEvent materialDemandEvent) { final IMutableMRPContext mrpContext = mkMRPContext(materialDemandEvent); @@ -134,7 +135,7 @@ private void handleMaterialDemandEvent(final MaterialDemandEvent materialDemandE final I_M_Locator toLocator = InterfaceWrapperHelper.create(mrpContext.getCtx(), ddOrderLine.getToLocatorId(), I_M_Locator.class, mrpContext.getTrxName()); final DistributionPlanEvent distributionPlanEvent = DistributionPlanEvent.builder() - .when(Instant.now()) + .eventDescr(new EventDescr()) .fromWarehouseId(fromLocator.getM_Warehouse_ID()) .distributionStart(orderLineStartDate) .materialDescr(MaterialDescriptor.builder() @@ -145,6 +146,7 @@ private void handleMaterialDemandEvent(final MaterialDemandEvent materialDemandE .warehouseId(toLocator.getM_Warehouse_ID()) .build()) .reference(materialDemandEvent.getReference()) + .orderLineId(materialDemandEvent.getOrderLineId()) .build(); materialEventService.fireEvent(distributionPlanEvent); @@ -165,7 +167,7 @@ private void handleMaterialDemandEvent(final MaterialDemandEvent materialDemandE } } - private IMutableMRPContext mkMRPContext(final MaterialDemandEvent materialDemandEvent) + private IMutableMRPContext mkMRPContext(@NonNull final MaterialDemandEvent materialDemandEvent) { final MaterialDescriptor descr = materialDemandEvent.getDescr(); @@ -208,7 +210,9 @@ private IMutableMRPContext mkMRPContext(final MaterialDemandEvent materialDemand return mrpContext; } - private IMaterialRequest mkRequest(final MaterialDemandEvent materialDemandEvent, final IMaterialPlanningContext mrpContext) + private IMaterialRequest mkRequest( + @NonNull final MaterialDemandEvent materialDemandEvent, + @NonNull final IMaterialPlanningContext mrpContext) { return new IMaterialRequest() { @@ -222,7 +226,7 @@ public BigDecimal getQtyToSupply() @Override public int getMRPDemandOrderLineSOId() { - return -1; + return materialDemandEvent.getOrderLineId(); } @Override diff --git a/de.metas.material/planning/src/main/java/de/metas/material/planning/model/interceptor/Main.java b/de.metas.material/planning/src/main/java/de/metas/material/planning/model/interceptor/Main.java index 16d3e6af86e..61fb1ec141a 100644 --- a/de.metas.material/planning/src/main/java/de/metas/material/planning/model/interceptor/Main.java +++ b/de.metas.material/planning/src/main/java/de/metas/material/planning/model/interceptor/Main.java @@ -3,6 +3,7 @@ import org.adempiere.ad.modelvalidator.AbstractModuleInterceptor; import org.adempiere.ad.modelvalidator.IModelValidationEngine; import org.compiere.Adempiere; +import org.compiere.Adempiere.RunMode; import org.compiere.model.I_AD_Client; import org.compiere.util.Ini; @@ -46,7 +47,7 @@ protected void registerInterceptors(final IModelValidationEngine engine, final I @Override protected void onAfterInit() { - if (Ini.isClient()) + if (Ini.getRunMode() != RunMode.BACKEND) { return; // event based material planning can only run in the backend as of now } @@ -55,5 +56,6 @@ protected void onAfterInit() final MaterialDemandListener materialDemandListener = Adempiere.getBean(MaterialDemandListener.class); materialEventService.registerListener(materialDemandListener); + materialEventService.subscribeToEventBus(); } } diff --git a/de.metas.material/planning/src/main/java/de/metas/material/planning/pporder/PPOrderPojoConverter.java b/de.metas.material/planning/src/main/java/de/metas/material/planning/pporder/PPOrderPojoConverter.java index 370f1447819..57dd7ce76a0 100644 --- a/de.metas.material/planning/src/main/java/de/metas/material/planning/pporder/PPOrderPojoConverter.java +++ b/de.metas.material/planning/src/main/java/de/metas/material/planning/pporder/PPOrderPojoConverter.java @@ -1,21 +1,11 @@ package de.metas.material.planning.pporder; -import java.math.BigDecimal; -import java.time.Instant; - -import org.adempiere.ad.trx.api.ITrx; -import org.adempiere.model.InterfaceWrapperHelper; -import org.adempiere.uom.api.IUOMConversionBL; -import org.adempiere.util.Services; import org.adempiere.util.lang.impl.TableRecordReference; -import org.compiere.model.I_C_UOM; -import org.compiere.model.I_M_Product; -import org.compiere.util.Env; -import org.eevolution.model.I_PP_Order; import org.eevolution.model.I_PP_Order_BOMLine; import org.springframework.stereotype.Service; -import de.metas.material.event.ProductionOrderRequested; +import de.metas.material.event.EventDescr; +import de.metas.material.event.PPOrderRequestedEvent; import de.metas.material.event.ProductionPlanEvent; import de.metas.material.event.ProductionPlanEvent.ProductionPlanEventBuilder; import de.metas.material.event.pporder.PPOrder; @@ -32,12 +22,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -46,24 +36,6 @@ @Service public class PPOrderPojoConverter { - -// public PPOrder asPPOrderPojo(@NonNull final I_PP_Order ppOrder) -// { -// return PPOrder.builder() -// .datePromised(ppOrder.getDatePromised()) -// .dateStartSchedule(ppOrder.getDateStartSchedule()) -// .orgId(ppOrder.getAD_Org_ID()) -// -// // .productPlanningId(productPlanningId) -// .plantId(ppOrder.getS_Resource_ID()) -// .productId(ppOrder.getM_Product_ID()) -// .quantity(ppOrder.getQtyOrdered()) -// .uomId(ppOrder.getC_UOM_ID()) -// .warehouseId(ppOrder.getM_Warehouse_ID()) -// -// .build(); -// } - public PPOrderLine asPPOrderLinePojo(@NonNull final I_PP_Order_BOMLine ppOrderBOMLine) { return PPOrderLine.builder() @@ -75,7 +47,7 @@ public PPOrderLine asPPOrderLinePojo(@NonNull final I_PP_Order_BOMLine ppOrderBO .build(); } - public PPOrder asPPOrderPojo(@NonNull final ProductionOrderRequested event) + public PPOrder asPPOrderPojo(@NonNull final PPOrderRequestedEvent event) { return event.getPpOrder(); } @@ -84,29 +56,11 @@ public ProductionPlanEvent asProductionPlanEvent( @NonNull final PPOrder ppOrder, @NonNull final TableRecordReference reference) { - final Integer orgId = ppOrder.getOrgId(); - final Integer warehouseId = ppOrder.getWarehouseId(); - - final BigDecimal productQty = convertQtyToProductUOM(ppOrder.getProductId(), ppOrder.getUomId(), ppOrder.getQuantity()); - - final ProductionPlanEventBuilder builder = ProductionPlanEvent.builder(); - builder - .when(Instant.now()) + final ProductionPlanEventBuilder builder = ProductionPlanEvent.builder() + .eventDescr(new EventDescr()) .reference(reference) .ppOrder(ppOrder); return builder.build(); } - - private BigDecimal convertQtyToProductUOM(final Integer productId, final Integer uomId, final BigDecimal quantity) - { - final IUOMConversionBL uomConversionBL = Services.get(IUOMConversionBL.class); - - final I_M_Product product = InterfaceWrapperHelper.create(Env.getCtx(), productId, I_M_Product.class, ITrx.TRXNAME_None); - final I_C_UOM uomSource = InterfaceWrapperHelper.create(Env.getCtx(), uomId, I_C_UOM.class, ITrx.TRXNAME_None); - - // in material-dispo we currently don't care for UOMs, so it always has to be the product's UOM. - final BigDecimal productQty = uomConversionBL.convertToProductUOM(Env.getCtx(), product, uomSource, quantity); - return productQty; - } } diff --git a/de.metas.material/planning/src/main/java/de/metas/material/planning/pporder/PPOrderPojoSupplier.java b/de.metas.material/planning/src/main/java/de/metas/material/planning/pporder/PPOrderPojoSupplier.java index 47c82852c8b..88df6ef6afe 100644 --- a/de.metas.material/planning/src/main/java/de/metas/material/planning/pporder/PPOrderPojoSupplier.java +++ b/de.metas.material/planning/src/main/java/de/metas/material/planning/pporder/PPOrderPojoSupplier.java @@ -123,7 +123,13 @@ public PPOrder supplyPPOrderPojo( .dateStartSchedule(dateStartSchedule) // // Qtys - .quantity(qtyToSupply); + .quantity(qtyToSupply) + + .orderLineId(request.getMRPDemandOrderLineSOId()) + // + // offer further advise :-) + .createPPOrder(productPlanningData.isCreatePlan()) + ; return ppOrderPojoBuilder.build(); } @@ -205,7 +211,7 @@ private I_PP_Product_BOM retriveAndVerifyBOM(@NonNull final PPOrder ppOrder) { final Date dateStartSchedule = ppOrder.getDateStartSchedule(); final Integer ppOrderProductId = ppOrder.getProductId(); - + final I_PP_Product_BOM productBOM = InterfaceWrapperHelper .create(Env.getCtx(), ppOrder.getProductPlanningId(), I_PP_Product_Planning.class, ITrx.TRXNAME_None) .getPP_Product_BOM(); diff --git a/de.metas.material/planning/src/main/java/de/metas/material/planning/pporder/impl/PPOrderBOMBL.java b/de.metas.material/planning/src/main/java/de/metas/material/planning/pporder/impl/PPOrderBOMBL.java index 9bf2ac9b53c..7f8c033d5f9 100644 --- a/de.metas.material/planning/src/main/java/de/metas/material/planning/pporder/impl/PPOrderBOMBL.java +++ b/de.metas.material/planning/src/main/java/de/metas/material/planning/pporder/impl/PPOrderBOMBL.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Properties; +import org.adempiere.ad.trx.api.ITrx; import org.adempiere.mm.attributes.api.IAttributeDAO; import org.adempiere.model.InterfaceWrapperHelper; import org.adempiere.uom.api.IUOMConversionBL; @@ -222,7 +223,7 @@ private void setQtyRequired(final I_PP_Order_BOMLine orderBOMLine, final BigDecimal qtyFinishedGood, final I_C_UOM qtyFinishedGoodUOM) { - final BigDecimal qtyRequired = calculateQtyRequired(orderBOMLine, qtyFinishedGood); + final BigDecimal qtyRequired = calculateQtyRequired(fromRecord(orderBOMLine), qtyFinishedGood); orderBOMLine.setQtyRequiered(qtyRequired); } @@ -236,7 +237,7 @@ private void setQtyRequired(final I_PP_Order_BOMLine orderBOMLine, */ @VisibleForTesting /* package */BigDecimal calculateQtyRequired( - @NonNull final I_PP_Order_BOMLine orderBOMLine, + @NonNull final PPOrderBomLineAware orderBOMLine, @NonNull final BigDecimal qtyFinishedGood) { final BigDecimal multiplier = getQtyMultiplier(orderBOMLine); @@ -277,7 +278,7 @@ public BigDecimal calculateQtyRequired( @NonNull final PPOrder ppOrderPojo, @NonNull final BigDecimal qtyFinishedGood) { - throw new UnsupportedOperationException("calculateQtyRequired"); + return calculateQtyRequired(fromPojo(ppOrderLinePojo), qtyFinishedGood); } @Override @@ -288,7 +289,7 @@ public BigDecimal calculateQtyRequiredProjected(final I_PP_Order_BOMLine orderBO final BigDecimal qtyDelivered_FinishedGood = ppOrder.getQtyDelivered(); final BigDecimal qtyRequiredActual_FinishedGood = qtyRequired_FinishedGood.max(qtyDelivered_FinishedGood); - return calculateQtyRequired(orderBOMLine, qtyRequiredActual_FinishedGood); + return calculateQtyRequired(fromRecord(orderBOMLine), qtyRequiredActual_FinishedGood); } @Override @@ -305,7 +306,7 @@ public Quantity calculateQtyToIssueBasedOnFinishedGoodReceipt( // // Calculate how much we can issue at max, based on how much finish goods we delivered - final BigDecimal qtyToIssueMax_InStdUOM = calculateQtyRequired(orderBOMLine, qtyDelivered_FinishedGood); + final BigDecimal qtyToIssueMax_InStdUOM = calculateQtyRequired(fromRecord(orderBOMLine), qtyDelivered_FinishedGood); if (qtyToIssueMax_InStdUOM.signum() <= 0) { return Quantity.zero(uom); @@ -327,6 +328,154 @@ public Quantity calculateQtyToIssueBasedOnFinishedGoodReceipt( return new Quantity(qtyToIssueEffective, uom, qtyToIssueEffective_InStdUOM, standardUOM); } + private interface PPOrderBomLineAware + { + + BigDecimal getQtyBOM(); + + I_M_Product getPPOrderBomProduct(); + + BigDecimal getScrap(); + + String getComponentType(); + + I_C_UOM getC_UOM(); + + BigDecimal getQtyBatch(); + + boolean isQtyPercentage(); + + I_C_UOM getPPOrderBomUOM(); + } + + @VisibleForTesting + PPOrderBomLineAware fromPojo(@NonNull final PPOrderLine ppOrderBOMLine) + { + return new PPOrderBomLineAware() + { + @Override + public boolean isQtyPercentage() + { + final I_PP_Product_BOMLine productBomLine = getProductBomLine(ppOrderBOMLine); + return productBomLine.isQtyPercentage(); + } + + private I_PP_Product_BOMLine getProductBomLine(@NonNull final PPOrderLine ppOrderBOMLine) + { + final I_PP_Product_BOMLine productBomLine = InterfaceWrapperHelper.create(Env.getCtx(), ppOrderBOMLine.getProductBomLineId(), I_PP_Product_BOMLine.class, ITrx.TRXNAME_None); + return productBomLine; + } + + @Override + public BigDecimal getScrap() + { + final I_PP_Product_BOMLine productBomLine = getProductBomLine(ppOrderBOMLine); + return productBomLine.getScrap(); + } + + @Override + public BigDecimal getQtyBatch() + { + final I_PP_Product_BOMLine productBomLine = getProductBomLine(ppOrderBOMLine); + return productBomLine.getQtyBatch(); + } + + @Override + public BigDecimal getQtyBOM() + { + final I_PP_Product_BOMLine productBomLine = getProductBomLine(ppOrderBOMLine); + return productBomLine.getQtyBOM(); + } + + @Override + public String getComponentType() + { + final I_PP_Product_BOMLine productBomLine = getProductBomLine(ppOrderBOMLine); + return productBomLine.getComponentType(); + } + + @Override + public I_C_UOM getC_UOM() + { + final I_PP_Product_BOMLine productBomLine = getProductBomLine(ppOrderBOMLine); + return productBomLine.getC_UOM(); + } + + @Override + public I_M_Product getPPOrderBomProduct() + { + final I_PP_Product_BOMLine productBomLine = getProductBomLine(ppOrderBOMLine); + return productBomLine + .getPP_Product_BOM() + .getM_Product(); + } + + @Override + public I_C_UOM getPPOrderBomUOM() + { + final I_PP_Product_BOMLine productBomLine = getProductBomLine(ppOrderBOMLine); + return productBomLine + .getPP_Product_BOM() + .getC_UOM(); + } + }; + } + + @VisibleForTesting + PPOrderBomLineAware fromRecord(@NonNull final I_PP_Order_BOMLine ppOrderBOMLine) + { + return new PPOrderBomLineAware() + { + @Override + public boolean isQtyPercentage() + { + return ppOrderBOMLine.isQtyPercentage(); + } + + @Override + public BigDecimal getQtyBatch() + { + return ppOrderBOMLine.getQtyBatch(); + } + + @Override + public BigDecimal getQtyBOM() + { + return ppOrderBOMLine.getQtyBOM(); + } + + @Override + public I_M_Product getPPOrderBomProduct() + { + return ppOrderBOMLine.getPP_Order_BOM().getM_Product(); + } + + @Override + public I_C_UOM getPPOrderBomUOM() + { + return ppOrderBOMLine.getPP_Order_BOM().getC_UOM(); + } + + @Override + public I_C_UOM getC_UOM() + { + return ppOrderBOMLine.getC_UOM(); + } + + @Override + public BigDecimal getScrap() + { + return ppOrderBOMLine.getScrap(); + } + + @Override + public String getComponentType() + { + return ppOrderBOMLine.getComponentType(); + } + }; + } + /** * Return Unified BOM Qty Multiplier. * @@ -336,7 +485,8 @@ public Quantity calculateQtyToIssueBasedOnFinishedGoodReceipt( * * @return If is percentage then QtyBatch / 100 will be returned, else QtyBOM. */ - /* package */BigDecimal getQtyMultiplier(final I_PP_Order_BOMLine orderBOMLine) + /* package */BigDecimal getQtyMultiplier( + @NonNull final PPOrderBomLineAware orderBOMLine) { BigDecimal qty; if (orderBOMLine.isQtyPercentage()) @@ -346,9 +496,8 @@ public Quantity calculateQtyToIssueBasedOnFinishedGoodReceipt( // // We also need to multiply by BOM UOM to BOM Line UOM multiplier // see http://dewiki908/mediawiki/index.php/06973_Fix_percentual_BOM_line_quantities_calculation_%28108941319640%29 - final I_PP_Order_BOM orderBOM = orderBOMLine.getPP_Order_BOM(); - final I_M_Product bomProduct = orderBOM.getM_Product(); - final I_C_UOM bomUOM = orderBOM.getC_UOM(); + final I_M_Product bomProduct = orderBOMLine.getPPOrderBomProduct(); + final I_C_UOM bomUOM = orderBOMLine.getPPOrderBomUOM(); final I_C_UOM bomLineUOM = orderBOMLine.getC_UOM(); Check.assumeNotNull(bomLineUOM, "bomLineUOM not null"); diff --git a/de.metas.material/planning/src/test/java/de/metas/material/planning/pporder/impl/PPOrderBOMBL_calculateQtyRequired_Test.java b/de.metas.material/planning/src/test/java/de/metas/material/planning/pporder/impl/PPOrderBOMBL_calculateQtyRequired_Test.java index c46a0c14a18..84bb7f179d4 100644 --- a/de.metas.material/planning/src/test/java/de/metas/material/planning/pporder/impl/PPOrderBOMBL_calculateQtyRequired_Test.java +++ b/de.metas.material/planning/src/test/java/de/metas/material/planning/pporder/impl/PPOrderBOMBL_calculateQtyRequired_Test.java @@ -89,7 +89,7 @@ private void createMasterData() ppOrder.setC_UOM(uomEa); PPOrderBOMBL_TestUtils.setCommonValues(ppOrder); - + // Component ppOrderBOMLine = InterfaceWrapperHelper.newInstance(I_PP_Order_BOMLine.class); ppOrderBOMLine.setPP_Order(ppOrder); @@ -137,7 +137,7 @@ public void test_calculateQtyRequiredProjected_OverReceipt() ppOrderBOMLine.setQtyDelivered(BigDecimal.ZERO); Assert.assertThat("Invalid QtyRequired projected", - ppOrderBOMBL.calculateQtyRequired(ppOrderBOMLine, ppOrder.getQtyOrdered()), + ppOrderBOMBL.calculateQtyRequired(ppOrderBOMBL.fromRecord(ppOrderBOMLine), ppOrder.getQtyOrdered()), // Expected: 100(finished goods) x 260(mm/finished good) x (scrap=1 + 10/100) Matchers.comparesEqualTo(new BigDecimal("28600"))); diff --git a/de.metas.material/planning/src/test/java/de/metas/material/planning/pporder/impl/PPOrderPojoConverterTests.java b/de.metas.material/planning/src/test/java/de/metas/material/planning/pporder/impl/PPOrderPojoConverterTests.java index 04572724eeb..0947d305f4b 100644 --- a/de.metas.material/planning/src/test/java/de/metas/material/planning/pporder/impl/PPOrderPojoConverterTests.java +++ b/de.metas.material/planning/src/test/java/de/metas/material/planning/pporder/impl/PPOrderPojoConverterTests.java @@ -21,7 +21,8 @@ import org.junit.Before; import org.junit.Test; -import de.metas.material.event.ProductionOrderRequested; +import de.metas.material.event.EventDescr; +import de.metas.material.event.PPOrderRequestedEvent; import de.metas.material.event.ProductionPlanEvent; import de.metas.material.event.pporder.PPOrder; import de.metas.material.event.pporder.PPOrderLine; @@ -37,12 +38,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -89,14 +90,14 @@ public void init() public void testPProductBOMStuff() { final I_PP_Product_BOM ppProductBom = InterfaceWrapperHelper.newInstance(I_PP_Product_BOM.class); - + InterfaceWrapperHelper.save(ppProductBom); } private void createProductBomLine() { final I_PP_Product_BOMLine ppProductBomLine = InterfaceWrapperHelper.newInstance(I_PP_Product_BOMLine.class); - + ppProductBomLine.setAssay(BigDecimal.valueOf(20)); ppProductBomLine.setBackflushGroup("backflushGroup"); ppProductBomLine.setComponentType(X_PP_Order_BOMLine.COMPONENTTYPE_Component); @@ -114,10 +115,10 @@ private void createProductBomLine() ppProductBomLine.setValidTo(new Timestamp(t4.getTime())); ppProductBomLine.setVariantGroup("variantGroup"); ppProductBomLine.setM_ChangeNotice_ID(120); - + InterfaceWrapperHelper.save(ppProductBomLine); } - + @Test public void test() { @@ -151,10 +152,10 @@ public void test() assertThat(productionPlanEvent, notNullValue()); - final ProductionOrderRequested productionOrderEvent = ProductionOrderRequested.builder() + final PPOrderRequestedEvent productionOrderEvent = PPOrderRequestedEvent.builder() + .eventDescr(new EventDescr()) .ppOrder(productionPlanEvent.getPpOrder()) .reference(productionPlanEvent.getReference()) - .when(productionPlanEvent.getWhen()) .build(); final PPOrder ppOrderPojoAfterConversion = ppOrderPojoConverter.asPPOrderPojo(productionOrderEvent); diff --git a/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/invoicecandidate/spi/impl/M_InOutLine_Handler.java b/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/invoicecandidate/spi/impl/M_InOutLine_Handler.java index de4321c0a1b..765ba641cf1 100644 --- a/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/invoicecandidate/spi/impl/M_InOutLine_Handler.java +++ b/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/invoicecandidate/spi/impl/M_InOutLine_Handler.java @@ -239,19 +239,9 @@ private I_C_Invoice_Candidate createCandidateForInOutLine(final I_M_InOutLine in final Timestamp billDate = inOut.getDateAcct(); final int locationId = inOut.getC_BPartner_Location_ID(); final int taxId = Services.get(ITaxBL.class).getTax( - ctx - , ic - , taxCategoryId - , productId - , chargeId - , billDate - , shipDate - , adOrgId - , inOut.getM_Warehouse() - , locationId // billC_BPartner_Location_ID + ctx, ic, taxCategoryId, productId, chargeId, billDate, shipDate, adOrgId, inOut.getM_Warehouse(), locationId // billC_BPartner_Location_ID , locationId // shipC_BPartner_Location_ID - , isSOTrx - , trxName); + , isSOTrx, trxName); ic.setC_Tax_ID(taxId); // @@ -319,7 +309,7 @@ public boolean isUserInChargeUserEditable() * * @param ic * @return - *

      + *
        *
      • +1 on regular shipment/receipt *
      • -1 on material returns *
      @@ -361,8 +351,9 @@ public void setOrderedData(final I_C_Invoice_Candidate ic) ic.setC_Order(order); // also set the order; even if the iol does not directly refer to an order line, it is there because of that order ic.setDateOrdered(order.getDateOrdered()); } - else + else if (ic.getC_Order_ID() <= 0) { + // don't attempt to "clear" the order data if it is already set/known. ic.setC_Order(null); ic.setDateOrdered(inOut.getMovementDate()); } diff --git a/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/material/model/interceptor/M_ReceiptSchedule.java b/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/material/model/interceptor/M_ReceiptSchedule.java index 03afe2cb386..782bfcc7eda 100644 --- a/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/material/model/interceptor/M_ReceiptSchedule.java +++ b/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/material/model/interceptor/M_ReceiptSchedule.java @@ -1,7 +1,5 @@ package de.metas.material.model.interceptor; -import java.time.Instant; - import org.adempiere.ad.modelvalidator.annotations.Interceptor; import org.adempiere.ad.modelvalidator.annotations.ModelChange; import org.adempiere.model.InterfaceWrapperHelper; @@ -10,6 +8,7 @@ import org.compiere.model.ModelValidator; import de.metas.inoutcandidate.model.I_M_ReceiptSchedule; +import de.metas.material.event.EventDescr; import de.metas.material.event.MaterialDescriptor; import de.metas.material.event.MaterialEventService; import de.metas.material.event.ReceiptScheduleEvent; @@ -31,7 +30,7 @@ public void fireEvent(final I_M_ReceiptSchedule schedule, final int timing) { final boolean deleted = timing == ModelValidator.TYPE_AFTER_DELETE; final ReceiptScheduleEvent event = ReceiptScheduleEvent.builder() - .when(Instant.now()) + .eventDescr(new EventDescr()) .reference(TableRecordReference.of(schedule)) .materialDescr(MaterialDescriptor.builder() .orgId(schedule.getAD_Org_ID()) diff --git a/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/material/model/interceptor/M_ShipmentSchedule.java b/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/material/model/interceptor/M_ShipmentSchedule.java index 9f85f6c1172..6bb5a96f093 100644 --- a/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/material/model/interceptor/M_ShipmentSchedule.java +++ b/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/material/model/interceptor/M_ShipmentSchedule.java @@ -1,7 +1,6 @@ package de.metas.material.model.interceptor; import java.sql.Timestamp; -import java.time.Instant; import org.adempiere.ad.modelvalidator.annotations.Interceptor; import org.adempiere.ad.modelvalidator.annotations.ModelChange; @@ -13,6 +12,7 @@ import de.metas.inoutcandidate.api.IShipmentScheduleEffectiveBL; import de.metas.inoutcandidate.model.I_M_ShipmentSchedule; +import de.metas.material.event.EventDescr; import de.metas.material.event.MaterialDescriptor; import de.metas.material.event.MaterialEventService; import de.metas.material.event.ShipmentScheduleEvent; @@ -45,7 +45,7 @@ private M_ShipmentSchedule() I_M_ShipmentSchedule.COLUMNNAME_AD_Org_ID, I_M_ShipmentSchedule.COLUMNNAME_PreparationDate_Override, I_M_ShipmentSchedule.COLUMNNAME_PreparationDate, - I_M_ShipmentSchedule.COLUMNNAME_IsActive /* IsActive=N shall be threaded like a deletion*/}) + I_M_ShipmentSchedule.COLUMNNAME_IsActive /* IsActive=N shall be threaded like a deletion */ }) public void fireEvent(final I_M_ShipmentSchedule schedule, final int timing) { final IShipmentScheduleEffectiveBL shipmentScheduleEffectiveBL = Services.get(IShipmentScheduleEffectiveBL.class); @@ -54,6 +54,7 @@ public void fireEvent(final I_M_ShipmentSchedule schedule, final int timing) final Timestamp preparationDate = shipmentScheduleEffectiveBL.getPreparationDate(schedule); final ShipmentScheduleEvent event = ShipmentScheduleEvent.builder() + .eventDescr(new EventDescr()) .materialDescr(MaterialDescriptor.builder() .orgId(schedule.getAD_Org_ID()) .date(preparationDate) @@ -63,7 +64,7 @@ public void fireEvent(final I_M_ShipmentSchedule schedule, final int timing) .build()) .reference(TableRecordReference.of(schedule)) .shipmentScheduleDeleted(deleted) - .when(Instant.now()) + .orderLineId(schedule.getC_OrderLine_ID()) .build(); final MaterialEventService materialEventService = Adempiere.getBean(MaterialEventService.class); diff --git a/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/material/model/interceptor/M_Transaction.java b/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/material/model/interceptor/M_Transaction.java index 33b1b268108..7944d54b0cb 100644 --- a/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/material/model/interceptor/M_Transaction.java +++ b/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/material/model/interceptor/M_Transaction.java @@ -1,7 +1,5 @@ package de.metas.material.model.interceptor; -import java.time.Instant; - import org.adempiere.ad.modelvalidator.annotations.Interceptor; import org.adempiere.ad.modelvalidator.annotations.ModelChange; import org.adempiere.model.InterfaceWrapperHelper; @@ -10,6 +8,7 @@ import org.compiere.model.I_M_Transaction; import org.compiere.model.ModelValidator; +import de.metas.material.event.EventDescr; import de.metas.material.event.MaterialDescriptor; import de.metas.material.event.MaterialEventService; import de.metas.material.event.TransactionEvent; @@ -57,7 +56,9 @@ private M_Transaction() public void enqueuePurchaseCandidates(final I_M_Transaction transaction, final int timing) { final TransactionEvent event = TransactionEvent.builder() + .eventDescr(new EventDescr()) .transactionDeleted(timing == ModelValidator.TYPE_BEFORE_DELETE) + .eventDescr(new EventDescr()) .materialDescr(MaterialDescriptor.builder() .orgId(transaction.getAD_Org_ID()) .warehouseId(transaction.getM_Locator().getM_Warehouse_ID()) @@ -66,7 +67,6 @@ public void enqueuePurchaseCandidates(final I_M_Transaction transaction, final i .qty(transaction.getMovementQty()) .build()) .reference(TableRecordReference.of(transaction)) - .when(Instant.now()) .build(); final MaterialEventService materialEventService = Adempiere.getBean(MaterialEventService.class); diff --git a/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/material/model/interceptor/Main.java b/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/material/model/interceptor/Main.java index 15d276d9363..511b85d891b 100644 --- a/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/material/model/interceptor/Main.java +++ b/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/material/model/interceptor/Main.java @@ -2,8 +2,11 @@ import org.adempiere.ad.modelvalidator.AbstractModuleInterceptor; import org.adempiere.ad.modelvalidator.IModelValidationEngine; +import org.compiere.Adempiere; import org.compiere.model.I_AD_Client; +import de.metas.material.event.MaterialEventService; + /* * #%L * de.metas.swat.base @@ -14,12 +17,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -28,10 +31,20 @@ public class Main extends AbstractModuleInterceptor { + @Override protected void registerInterceptors(final IModelValidationEngine engine, final I_AD_Client client) { engine.addModelValidator(M_ReceiptSchedule.INSTANCE, client); engine.addModelValidator(M_ShipmentSchedule.INSTANCE, client); engine.addModelValidator(M_Transaction.INSTANCE, client); } + + @Override + protected void onAfterInit() + { + // add ourselves to the eventbus so that we can fire events, + final MaterialEventService materialEventService = Adempiere.getBean(MaterialEventService.class); + materialEventService.subscribeToEventBus(); + } + } diff --git a/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/ordercandidate/process/C_OLCand_Validate_Selected.java b/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/ordercandidate/process/C_OLCand_Validate_Selected.java index e6ec7d96f13..40732e8c628 100644 --- a/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/ordercandidate/process/C_OLCand_Validate_Selected.java +++ b/de.metas.swat/de.metas.swat.base/src/main/java/de/metas/ordercandidate/process/C_OLCand_Validate_Selected.java @@ -10,12 +10,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -55,7 +55,6 @@ protected void prepare() @Override protected String doIt() throws Exception { - getProcessInfo().getQueryFilter(); final IQueryFilter queryFilter = getProcessInfo().getQueryFilter(); final IQueryBuilder queryBuilder = queryBL.createQueryBuilder(I_C_OLCand.class, getCtx(), get_TrxName())