diff --git a/de.metas.contracts/src/main/java/de/metas/contracts/IFlatrateBL.java b/de.metas.contracts/src/main/java/de/metas/contracts/IFlatrateBL.java index da5af3af4c9..66c99a281be 100644 --- a/de.metas.contracts/src/main/java/de/metas/contracts/IFlatrateBL.java +++ b/de.metas.contracts/src/main/java/de/metas/contracts/IFlatrateBL.java @@ -198,11 +198,21 @@ I_C_Flatrate_Term createTerm(IContextAware context, void voidIt(I_C_Flatrate_Term term); /** - * Check if there are terms for the same that have a time period overlapping with the given term and match with the same product or product category. + * Return {@code true} if the given term (by virtue of its conditions-type) does not define a set of invoice candidates that "belong" to it. + * Examples for ICs that belong to a contract in this sense are e.g. ICs that shall trigger a refund, a commission payment or are empties (e.g. empty pallets). + * In all this cases, a completed term matches a set of ICs and for every given ICs, we need to make sure that max. one term matches it. * + * Also see {@link #hasOverlappingTerms(I_C_Flatrate_Term)}. + */ + boolean isAllowedToOverlapWithOtherTerms(I_C_Flatrate_Term term); + + /** + * Check if there are terms for the same bPartner that have a time period overlapping with the given term and match with the same product or product category. + *

+ * Note that overlapping need to be prevented for those types of terms (like refund contracts or refundable contracts) to which newly created invoice candidates need to be mapped. + * Overlapping is no problem for subscription contracts. * - * @param term - * @return + * Also see {@link #isAllowedToOverlapWithOtherTerms(I_C_Flatrate_Term)}. */ boolean hasOverlappingTerms(final I_C_Flatrate_Term term); diff --git a/de.metas.contracts/src/main/java/de/metas/contracts/IFlatrateDAO.java b/de.metas.contracts/src/main/java/de/metas/contracts/IFlatrateDAO.java index 90387d2fe1a..6c436dc50ab 100644 --- a/de.metas.contracts/src/main/java/de/metas/contracts/IFlatrateDAO.java +++ b/de.metas.contracts/src/main/java/de/metas/contracts/IFlatrateDAO.java @@ -155,7 +155,7 @@ public interface IFlatrateDAO extends ISingletonService void updateQtyActualFromDataEntry(I_C_Flatrate_DataEntry dataEntry); /** - * Retrieves the flatrate term matching the given invoice candidate or null.
+ * Retrieves the flatrate term matching the given invoice candidate (or {@code code>}) by using {@link I_C_Flatrate_Matching} Records.
* Basically calls {@link #retrieveTerms(Properties, int, Timestamp, int, int, int, String)}, but discards all terms that have IsSimulation=Y. * * @return the term or null diff --git a/de.metas.contracts/src/main/java/de/metas/contracts/impl/FlatrateBL.java b/de.metas.contracts/src/main/java/de/metas/contracts/impl/FlatrateBL.java index 543af1d31c3..423a49a3d1b 100644 --- a/de.metas.contracts/src/main/java/de/metas/contracts/impl/FlatrateBL.java +++ b/de.metas.contracts/src/main/java/de/metas/contracts/impl/FlatrateBL.java @@ -1553,17 +1553,19 @@ public void complete(final I_C_Flatrate_Term term) @Override public void completeIfValid(final I_C_Flatrate_Term term) { - final boolean hasOverlappingTerms = hasOverlappingTerms(term); - if (hasOverlappingTerms) + if (!isAllowedToOverlapWithOtherTerms(term)) { + final boolean hasOverlappingTerms = hasOverlappingTerms(term); + if (hasOverlappingTerms) + { - Loggables.get().addLog(Services.get(IMsgBL.class).getMsg( - Env.getCtx(), - MSG_HasOverlapping_Term, - new Object[] { term.getC_Flatrate_Term_ID(), term.getBill_BPartner().getValue() })); - return; + Loggables.get().addLog(Services.get(IMsgBL.class).getMsg( + Env.getCtx(), + MSG_HasOverlapping_Term, + new Object[] { term.getC_Flatrate_Term_ID(), term.getBill_BPartner().getValue() })); + return; + } } - complete(term); } @@ -1575,6 +1577,18 @@ public void voidIt(final I_C_Flatrate_Term term) } + @Override + public boolean isAllowedToOverlapWithOtherTerms(@NonNull final I_C_Flatrate_Term term) + { + final String typeConditions = term.getType_Conditions(); + + // These contract types do not match "other" ICs such as ICs that trigger a commission, or IC that belong to a vendor's empty package (pallette/TU). + // Therefore they can overlap without causing us any problems. + final boolean allowedToOverlapWithOtherTerms = X_C_Flatrate_Term.TYPE_CONDITIONS_Subscription.equals(typeConditions) + || X_C_Flatrate_Term.TYPE_CONDITIONS_Procurement.equals(typeConditions); + return allowedToOverlapWithOtherTerms; + } + @Override public boolean hasOverlappingTerms(final I_C_Flatrate_Term newTerm) { diff --git a/de.metas.contracts/src/main/java/de/metas/contracts/interceptor/C_Flatrate_Term.java b/de.metas.contracts/src/main/java/de/metas/contracts/interceptor/C_Flatrate_Term.java index 92642f05353..e024003f95c 100644 --- a/de.metas.contracts/src/main/java/de/metas/contracts/interceptor/C_Flatrate_Term.java +++ b/de.metas.contracts/src/main/java/de/metas/contracts/interceptor/C_Flatrate_Term.java @@ -493,6 +493,10 @@ public void preventOverlappingTerms_OnComplete(final I_C_Flatrate_Term term) // services final IFlatrateBL flatrateBL = Services.get(IFlatrateBL.class); + if (flatrateBL.isAllowedToOverlapWithOtherTerms(term)) + { + return; + } final boolean hasOverlappingTerms = flatrateBL.hasOverlappingTerms(term); if (hasOverlappingTerms) { @@ -518,7 +522,7 @@ private void setMasterEndDate(final I_C_Flatrate_Term term) term.setMasterEndDate(masterEndDate); } - + private Timestamp computeMasterEndDateIfC_FlatrateTerm_Next_IDChanged(@NonNull final I_C_Flatrate_Term term, Timestamp masterEndDate) { if (InterfaceWrapperHelper.isValueChanged(term, I_C_Flatrate_Term.COLUMNNAME_C_FlatrateTerm_Next_ID) && !term.isAutoRenew()) @@ -532,7 +536,7 @@ private Timestamp computeMasterEndDateIfC_FlatrateTerm_Next_IDChanged(@NonNull f masterEndDate = term.getEndDate(); } } - + return masterEndDate; } }