Skip to content

Commit

Permalink
#6566 customer retention logic refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
metas-rc committed May 5, 2020
1 parent 95fbbb7 commit 75ba36f
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 120 deletions.
@@ -0,0 +1,58 @@
package de.metas.contracts;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;

import de.metas.util.Check;
import de.metas.util.lang.RepoIdAware;

/*
* #%L
* de.metas.contracts
* %%
* Copyright (C) 2020 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
* <http://www.gnu.org/licenses/gpl-2.0.html>.
* #L%
*/

public class CustomerRetentionId implements RepoIdAware
{
int repoId;

@JsonCreator
public static CustomerRetentionId ofRepoId(final int repoId)
{
return new CustomerRetentionId(repoId);
}

public static CustomerRetentionId ofRepoIdOrNull(final int repoId)
{
return repoId > 0 ? ofRepoId(repoId) : null;
}

private CustomerRetentionId(final int repoId)
{
this.repoId = Check.assumeGreaterThanZero(repoId, "repoId");
}

@Override
@JsonValue
public int getRepoId()
{
return repoId;
}

}
@@ -1,6 +1,7 @@
package de.metas.contracts.impl;

import static org.adempiere.model.InterfaceWrapperHelper.delete;
import static org.adempiere.model.InterfaceWrapperHelper.load;
import static org.adempiere.model.InterfaceWrapperHelper.newInstance;
import static org.adempiere.model.InterfaceWrapperHelper.save;

Expand All @@ -11,20 +12,26 @@
import org.adempiere.ad.dao.IQueryBL;
import org.adempiere.invoice.service.IInvoiceDAO;
import org.adempiere.service.ISysConfigBL;
import org.compiere.SpringContextHolder;
import org.compiere.model.I_C_BPartner;
import org.compiere.model.I_C_Customer_Retention;
import org.compiere.model.I_C_Invoice;
import org.compiere.model.I_C_Order;
import org.compiere.model.X_C_Customer_Retention;
import org.compiere.util.TimeUtil;
import org.springframework.stereotype.Repository;

import com.google.common.collect.ImmutableSet;

import de.metas.bpartner.BPartnerId;
import de.metas.contracts.CustomerRetentionId;
import de.metas.contracts.IContractsDAO;
import de.metas.contracts.invoice.ContractInvoiceService;
import de.metas.contracts.model.I_C_Flatrate_Term;
import de.metas.contracts.order.ContractOrderService;
import de.metas.invoice.InvoiceId;
import de.metas.order.IOrderDAO;
import de.metas.order.OrderId;
import de.metas.util.Check;
import de.metas.util.Services;
import de.metas.util.lang.CoalesceUtil;
Expand Down Expand Up @@ -64,13 +71,19 @@ public class CustomerRetentionRepository
private final IInvoiceDAO invoiceDAO = Services.get(IInvoiceDAO.class);
private final IContractsDAO contractsDAO = Services.get(IContractsDAO.class);
private final ContractInvoiceService contractInvoiceService;


public I_C_Customer_Retention getById(final CustomerRetentionId customerRetentionId)
{

return load(customerRetentionId.getRepoId(), I_C_Customer_Retention.class);
}

public CustomerRetentionRepository(@NonNull final ContractInvoiceService contractInvoiceService)
{
this.contractInvoiceService = contractInvoiceService;
}

public I_C_Customer_Retention createNewCustomerRetention(@NonNull final BPartnerId bpartnerId)
public CustomerRetentionId createEmptyCustomerRetention(@NonNull final BPartnerId bpartnerId)
{
final I_C_Customer_Retention customerRetention = newInstance(I_C_Customer_Retention.class);

Expand All @@ -80,63 +93,66 @@ public I_C_Customer_Retention createNewCustomerRetention(@NonNull final BPartner

save(customerRetention);

return customerRetention;
return CustomerRetentionId.ofRepoId(customerRetention.getC_Customer_Retention_ID());
}

public void setNewCustomer(@NonNull final BPartnerId bpartnerId)
public void setNewCustomer(@NonNull final CustomerRetentionId customerRetentionId)
{
I_C_Customer_Retention customerRetention = retrieveCustomerRetention(bpartnerId);

if (customerRetention == null)
{
customerRetention = createNewCustomerRetention(bpartnerId);
}
final I_C_Customer_Retention customerRetention = getById(customerRetentionId);

customerRetention.setCustomerRetention(X_C_Customer_Retention.CUSTOMERRETENTION_Neukunde);
save(customerRetention);
}

public void setRegularCustomer(@NonNull final BPartnerId bpartnerId)
public void setRegularCustomer(@NonNull final CustomerRetentionId customerRetentionId)
{
I_C_Customer_Retention customerRetention = retrieveCustomerRetention(bpartnerId);

if (customerRetention == null)
{
customerRetention = createNewCustomerRetention(bpartnerId);
}
final I_C_Customer_Retention customerRetention = getById(customerRetentionId);

customerRetention.setCustomerRetention(X_C_Customer_Retention.CUSTOMERRETENTION_Stammkunde);
save(customerRetention);
}

public void setNonSubscriptionCustomer(@NonNull final BPartnerId bpartnerId)
public void setNonSubscriptionCustomer(@NonNull final CustomerRetentionId customerRetentionId)
{
final I_C_Customer_Retention customerRetention = retrieveCustomerRetention(bpartnerId);
final I_C_Customer_Retention customerRetention = getById(customerRetentionId);

customerRetention.setCustomerRetention(null);
save(customerRetention);
}

public I_C_Customer_Retention retrieveCustomerRetention(@NonNull final BPartnerId bpartnerId)
public CustomerRetentionId retrieveOrCreateCustomerRetention(@NonNull final BPartnerId bpartnerId)
{
final I_C_Customer_Retention firstOnly = queryBL.createQueryBuilder(I_C_Customer_Retention.class)
final I_C_Customer_Retention customerRetention = retrieveExistingCustomerRetention(bpartnerId);

if (customerRetention != null)
{
return CustomerRetentionId.ofRepoId(customerRetention.getC_Customer_Retention_ID());
}

return createEmptyCustomerRetention(bpartnerId);

}

public I_C_Customer_Retention retrieveExistingCustomerRetention(@NonNull final BPartnerId bpartnerId)
{
final I_C_Customer_Retention existingCustomerRetention = queryBL.createQueryBuilder(I_C_Customer_Retention.class)
.addOnlyActiveRecordsFilter()
.addOnlyContextClient()
.addEqualsFilter(I_C_Customer_Retention.COLUMN_C_BPartner_ID, bpartnerId.getRepoId())
.addEqualsFilter(I_C_Customer_Retention.COLUMNNAME_C_BPartner_ID, bpartnerId.getRepoId())
.create()
.firstOnly(I_C_Customer_Retention.class);
if (firstOnly != null)
{
return firstOnly;
}
else
{
return createNewCustomerRetention(bpartnerId);
}

return existingCustomerRetention;

}

public boolean isNewCustomer(@NonNull final BPartnerId bpartnerId)
{
final I_C_Customer_Retention customerRetention = retrieveCustomerRetention(bpartnerId);
final I_C_Customer_Retention customerRetention = retrieveExistingCustomerRetention(bpartnerId);

if (customerRetention == null)
{
return false;
}

final String currentCustomerRetention = customerRetention.getCustomerRetention();

Expand All @@ -147,7 +163,6 @@ public ImmutableSet<BPartnerId> retrieveBPartnerIdsWithCustomerRetention()
{
return queryBL.createQueryBuilder(I_C_Customer_Retention.class)
.addOnlyActiveRecordsFilter()
.addOnlyContextClient()
.addNotNull(I_C_Customer_Retention.COLUMN_CustomerRetention)
.andCollect(I_C_Customer_Retention.COLUMN_C_BPartner_ID, I_C_BPartner.class)
.create()
Expand All @@ -159,55 +174,55 @@ public int retrieveCustomerRetentionThreshold()
return sysConfigBL.getIntValue(SYS_CONFIG_C_CUSTOMER_RETENTION_Threshold, DEFAULT_Threshold_CustomerRetention);
}

public boolean hasCustomerRetention(final BPartnerId bpartnerId)
public boolean hasCustomerRetention(@NonNull final BPartnerId bpartnerId)
{
return !Check.isEmpty(retrieveCustomerRetention(bpartnerId));
return !Check.isEmpty(retrieveExistingCustomerRetention(bpartnerId));
}

public void updateCustomerRetention(final BPartnerId bpartnerId)
public void updateCustomerRetention(@NonNull final BPartnerId bpartnerId)
{
final CustomerRetentionId customerRetentionId = retrieveOrCreateCustomerRetention(bpartnerId);

final I_C_Flatrate_Term latestFlatrateTermForBPartnerId = contractsDAO.retrieveLatestFlatrateTermForBPartnerId(bpartnerId);

if (latestFlatrateTermForBPartnerId == null)
if (Check.isEmpty(latestFlatrateTermForBPartnerId))
{
// nothing to change and should not happen
return;
}

final Timestamp contractEndDate = CoalesceUtil.coalesce(latestFlatrateTermForBPartnerId.getMasterEndDate(), latestFlatrateTermForBPartnerId.getEndDate());

if (dateExceedsThreshold(contractEndDate, SystemTime.asTimestamp()))
{
setNonSubscriptionCustomer(bpartnerId);
setNonSubscriptionCustomer(customerRetentionId);

return;
}
else
{
setNewCustomer(bpartnerId);
setNewCustomer(customerRetentionId);
}

final InvoiceId lastSalesContractInvoiceId = contractInvoiceService.retrieveLastSalesContractInvoiceId(bpartnerId);

if (!Check.isEmpty(lastSalesContractInvoiceId))
{
updateCustomerRetentionAfterInvoiceId(bpartnerId, lastSalesContractInvoiceId);
updateCustomerRetentionAfterInvoiceId(customerRetentionId, lastSalesContractInvoiceId);
}

}

public boolean dateExceedsThreshold(final Timestamp contractEndDate, Timestamp dateToCompare)
public boolean dateExceedsThreshold(@NonNull final Timestamp contractEndDate, @NonNull final Timestamp dateToCompare)
{
final LocalDate currentDate = TimeUtil.asLocalDate(dateToCompare);
final LocalDate contractEndLocalDate = TimeUtil.asLocalDate(contractEndDate);

final int customerRetentionThreshold = retrieveCustomerRetentionThreshold();

return currentDate.minusMonths(customerRetentionThreshold).isAfter(contractEndLocalDate);

}

public void updateCustomerRetentionOnInvoiceComplete(final InvoiceId invoiceId)
public void updateCustomerRetentionOnInvoiceComplete(@NonNull final InvoiceId invoiceId)
{
if (!contractInvoiceService.isContractSalesInvoice(invoiceId))
{
Expand All @@ -218,27 +233,28 @@ public void updateCustomerRetentionOnInvoiceComplete(final InvoiceId invoiceId)
final I_C_Invoice invoice = invoiceDAO.getByIdInTrx(invoiceId);
final BPartnerId bpartnerId = BPartnerId.ofRepoId(invoice.getC_BPartner_ID());

if (!hasCustomerRetention(bpartnerId))
{
createNewCustomerRetention(bpartnerId);
}
final CustomerRetentionId customerRetentionId = retrieveOrCreateCustomerRetention(bpartnerId);

if (!isNewCustomer(bpartnerId))
{
// only change bpartners that are already marked as "New Customer"
return;
}
/*
* if (!isNewCustomer(bpartnerId))
* {
* // only change bpartners that are already marked as "New Customer" TODO WHY
* return;
* }
*/

updateCustomerRetentionAfterInvoiceId(bpartnerId, invoiceId);
updateCustomerRetentionAfterInvoiceId(customerRetentionId, invoiceId);
}

private void updateCustomerRetentionAfterInvoiceId(final BPartnerId bpartnerId, final InvoiceId invoiceId)
private void updateCustomerRetentionAfterInvoiceId(@NonNull final CustomerRetentionId customerRetentionId, @NonNull final InvoiceId invoiceId)
{

// TODO Compare with masterenddate from contract!!!
final InvoiceId predecessorSalesContractInvoiceId = contractInvoiceService.retrievePredecessorSalesContractInvoiceId(invoiceId);

if (Check.isEmpty(predecessorSalesContractInvoiceId))
{
setNewCustomer(bpartnerId);
setNewCustomer(customerRetentionId);
}
else
{
Expand All @@ -250,20 +266,46 @@ private void updateCustomerRetentionAfterInvoiceId(final BPartnerId bpartnerId,

if (dateExceedsThreshold(predecessorInvoiceDate, lastInvoiceDate))
{
setNewCustomer(bpartnerId);
setNewCustomer(customerRetentionId);
}

else
{
setRegularCustomer(bpartnerId);
setRegularCustomer(customerRetentionId);
}
}

}

public void deteleCustomerRetention(final BPartnerId bpartnerId)
public void deteleCustomerRetention(@NonNull final BPartnerId bpartnerId)
{
final I_C_Customer_Retention customerRetention = retrieveCustomerRetention(bpartnerId);
final I_C_Customer_Retention customerRetention = retrieveExistingCustomerRetention(bpartnerId);

delete(customerRetention);
}

public void updateCustomerRetentionOnOrderComplete(@NonNull final OrderId orderId)
{
final ContractOrderService contractOrderService = SpringContextHolder.instance.getBean(ContractOrderService.class);
final IOrderDAO orderDAO = Services.get(IOrderDAO.class);

if (!contractOrderService.isContractSalesOrder(orderId))
{
// nothing to do
return;
}

final I_C_Order order = orderDAO.getById(orderId);

final BPartnerId bpartnerId = BPartnerId.ofRepoId(order.getC_BPartner_ID());

final CustomerRetentionId customerRetentionId = retrieveOrCreateCustomerRetention(bpartnerId);

final I_C_Customer_Retention customerRetentionRecord = getById(customerRetentionId);

if (Check.isEmpty(customerRetentionRecord.getCustomerRetention()))
{
setNewCustomer(customerRetentionId);
}

}
}
Expand Up @@ -45,7 +45,7 @@ public class C_BPartner
public void createC_CustomerRetention(@NonNull final I_C_BPartner bpartner)
{
final BPartnerId bpartnerId = BPartnerId.ofRepoId(bpartner.getC_BPartner_ID());
bpartnerTimeSpanRepo.createNewCustomerRetention(bpartnerId);
bpartnerTimeSpanRepo.createEmptyCustomerRetention(bpartnerId);
}


Expand Down

0 comments on commit 75ba36f

Please sign in to comment.