Skip to content

Commit

Permalink
[AD-20] Recurring payment for subscription
Browse files Browse the repository at this point in the history
  • Loading branch information
kpieloch committed Oct 30, 2023
1 parent fa18d69 commit 2589085
Show file tree
Hide file tree
Showing 22 changed files with 994 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ public OrderData authorisePayment(final HttpServletRequest request, final CartDa
CheckoutPaymentsAction action = paymentsResponse.getAction();

LOGGER.info("Authorize payment with result code: " + resultCode + " action: " + (action != null ? action.getType() : "null"));

// TODO: Put token on order!
if (PaymentsResponse.ResultCodeEnum.AUTHORISED == resultCode || PaymentsResponse.ResultCodeEnum.PENDING == resultCode) {
return createAuthorizedOrder(paymentsResponse);
}
Expand Down Expand Up @@ -533,7 +533,9 @@ public OrderData handle3DSResponse(final Map<String, String> details) throws Exc
private OrderData createAuthorizedOrder(final PaymentsResponse paymentsResponse) throws InvalidCartException {
final CartModel cartModel = cartService.getSessionCart();
final String merchantTransactionCode = cartModel.getCode();

if(!paymentsResponse.getAdditionalData().isEmpty()&&paymentsResponse.getAdditionalData().containsKey("recurring.recurringDetailReference")) {
cartModel.getPaymentInfo().setAdyenSelectedReference(paymentsResponse.getAdditionalData().get("recurring.recurringDetailReference"));
}
//First save the transactions to the CartModel < AbstractOrderModel
getAdyenTransactionService().authorizeOrderModel(cartModel, merchantTransactionCode, paymentsResponse.getPspReference());

Expand Down Expand Up @@ -580,6 +582,7 @@ private OrderData fillOrderDataWithPaymentInfo(OrderData orderData, PaymentsResp

if (paymentsResponse.getAdditionalData() != null) {
orderData.setAdyenPosReceipt(paymentsResponse.getAdditionalData().get("pos.receipt"));
//orderData.getPaymentInfo().setgetPaymentInfo().set
}

return orderData;
Expand Down
2 changes: 1 addition & 1 deletion adyenv6core/src/com/adyen/v6/model/RequestInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public RequestInfo(HttpServletRequest request) {
this.origin = getOrigin(request);
}

private RequestInfo() {
public RequestInfo() {
}

public String getOrigin(HttpServletRequest request) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ public void testAuthorise() {
testRecurringOption(RecurringContractMode.NONE, null);
testRecurringOption(RecurringContractMode.ONECLICK, null);
//testRecurringOption(RecurringContractMode.RECURRING, Recurring.ContractEnum.RECURRING);
//testRecurringOption(RecurringContractMode.ONECLICK_RECURRING, Recurring.ContractEnum.RECURRING);
//testRecurringOption(RecurringContractMode.RECURRING, Recurring.ContractEnum.RECURRING);

//Test recurring contract when remember-me is set
when(cartDataMock.getAdyenRememberTheseDetails()).thenReturn(true);
Expand Down
11 changes: 2 additions & 9 deletions adyenv6subscription/extensioninfo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,10 @@
<requires-extension name="commercefacades"/>
<requires-extension name="basecommerce"/>
<requires-extension name="adyenv6core"/>

<requires-extension name="subscriptionservices"/>


<coremodule generated="true" manager="com.adyen.v6.jalo.Adyenv6subscriptionManager" packageroot="com.adyen.v6"/>


<webmodule jspcompile="false" webroot="/adyenv6subscription"/>





</extension>


Expand Down
3 changes: 3 additions & 0 deletions adyenv6subscription/resources/adyenv6subscription-beans.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="beans.xsd">

<bean class="de.hybris.platform.commercefacades.order.data.AbstractOrderData">
<property name="subscriptionOrder" type="java.lang.Boolean" />
</bean>

</beans>
25 changes: 25 additions & 0 deletions adyenv6subscription/resources/adyenv6subscription-items.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@
</attributes>
</itemtype>

<itemtype code="AbstractOrder" autocreate="false" generate="false">
<attributes>
<attribute type="java.lang.Boolean" qualifier="subscriptionOrder">
<description>If the order is generated by subscription job</description>
<persistence type="property" />
<modifiers optional="true" unique="false" write="true" read="true" />
</attribute>
</attributes>
</itemtype>

<itemtype code="BaseStore" generate="false" autocreate="false">
<attributes>
<attribute qualifier="subscriptionAllowedPaymentMethods" type="SubscriptionAllowedPaymentMethods" >
Expand All @@ -35,5 +45,20 @@
</attributes>
</itemtype>

<itemtype code="Subscription" autocreate="false" generate="false">
<attributes>
<attribute type="Order" qualifier="subscriptionOrder">
<description>The order the subcription is created from</description>
<persistence type="property" />
<modifiers optional="false" unique="false" write="true" read="true" />
</attribute>
<attribute qualifier="nextChargeDate" type="java.util.Date">
<description>The next date that customer should be charged</description>
<modifiers read="true" write="true" search="true" optional="true" unique="false"/>
<persistence type="property"/>
</attribute>
</attributes>
</itemtype>

</itemtypes>
</items>
44 changes: 44 additions & 0 deletions adyenv6subscription/resources/adyenv6subscription-spring.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,48 @@
<property name="cartFacade" ref="cartFacade" />
</bean>

<bean id="subscriptionRepository" class="com.adyen.v6.repository.SubscriptionRepository" >
<property name="flexibleSearchService" ref="flexibleSearchService" />
</bean>

<bean id="subscriptionOrderExecutor" class="com.adyen.v6.service.impl.SubscriptionOrderExecutor" scope="prototype">
<constructor-arg value="originalOrder" />
<property name="cartService" ref="defaultCartService" />
<property name="typeService" ref="typeService" />
<property name="adyenPaymentServiceFactory" ref="adyenPaymentServiceFactory" />
<property name="adyenTransactionService" ref="adyenTransactionService" />
<property name="cartConverter" ref="cartConverter" />
<property name="commerceCheckoutService" ref="commerceCheckoutService" />
<property name="baseStoreService" ref="baseStoreService" />
<property name="modelService" ref="modelService" />
<property name="keyGenerator" ref="orderCodeGenerator" />
<property name="subscriptionAdyenPaymentServiceFactory" ref="subscriptionAdyenPaymentServiceFactory" />
</bean>

<alias alias="subscriptionCommercePlaceOrderMethodHook" name="adyenSubscriptionCommercePlaceOrderMethodHook"/>
<bean id="adyenSubscriptionCommercePlaceOrderMethodHook"
class="com.adyen.v6.hooks.AdyenSubscriptionCommercePlaceOrderMethodHook"
parent="defaultSubscriptionCommercePlaceOrderMethodHook">

</bean>

<bean id="adyenSubscriptionOrderPopulator" class="com.adyen.v6.populators.AdyenSubscriptionOrderPopulator" parent="baseOrderPopulator">
</bean>

<bean id="recurringOrderService" class="com.adyen.v6.service.impl.DefaultRecurringOrderService">
<property name="impersonationService" ref="impersonationService"/>
</bean>

<bean id="subscriptionCronJob" class="com.adyen.v6.job.SubscriptionCronJob" parent="abstractJobPerformable" >
<property name="modelService" ref="modelService"/>
<property name="subscriptionRepository" ref="subscriptionRepository" />
<property name="recurringOrderService" ref="recurringOrderService" />
</bean>

<alias alias="recurringOrdersCloneAbstractOrderHook" name="adyenRecurringOrdersCloneAbstractOrderHook"/>
<bean id="adyenRecurringOrdersCloneAbstractOrderHook" class="com.adyen.v6.hooks.AdyenRecurringOrdersCloneAbstractOrderHook">
<property name="itemModelCloneCreator" ref="itemModelCloneCreator"/>
<property name="modelService" ref="modelService"/>
</bean>

</beans>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
INSERT_UPDATE CronJob; code[unique=true];job(code);singleExecutable;sessionLanguage(isocode)
;subscriptionCronJob;subscriptionCronJob;false;en

INSERT_UPDATE Trigger;cronjob(code)[unique=true];cronExpression
;subscriptionCronJob; 0 0 2 * * ?
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,144 @@

import com.adyen.model.checkout.PaymentMethodDetails;
import com.adyen.model.checkout.PaymentsRequest;
import com.adyen.model.checkout.details.CardDetails;
import com.adyen.model.recurring.RecurringDetailsRequest;
import com.adyen.util.Util;
import com.adyen.v6.constants.Adyenv6coreConstants;
import com.adyen.v6.enums.RecurringContractMode;
import com.adyen.v6.model.RequestInfo;
import com.adyen.v6.paymentmethoddetails.executors.AdyenPaymentMethodDetailsBuilderExecutor;
import com.adyen.v6.utils.SubscriptionsUtils;
import de.hybris.platform.commercefacades.order.CartFacade;
import de.hybris.platform.commercefacades.order.data.CartData;
import de.hybris.platform.commercefacades.user.data.AddressData;
import de.hybris.platform.core.model.user.CustomerModel;
import de.hybris.platform.servicelayer.config.ConfigurationService;
import org.apache.commons.lang3.BooleanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import org.springframework.web.bind.annotation.RequestMethod;


public class SubscriptionPaymentRequestFactory extends AdyenRequestFactory {

private static final Logger LOG = LoggerFactory.getLogger(SubscriptionPaymentRequestFactory.class);

@Resource(name = "cartFacade")
private CartFacade cartFacade;

public SubscriptionPaymentRequestFactory(ConfigurationService configurationService, AdyenPaymentMethodDetailsBuilderExecutor adyenPaymentMethodDetailsBuilderExecutor) {
super(configurationService, adyenPaymentMethodDetailsBuilderExecutor);
}

@Override
public PaymentsRequest createPaymentsRequest(String merchantAccount, CartData cartData, RequestInfo requestInfo, CustomerModel customerModel, RecurringContractMode recurringContractMode, Boolean guestUserTokenizationEnabled) {
PaymentsRequest paymentsRequest = super.createPaymentsRequest(merchantAccount, cartData, requestInfo, customerModel, recurringContractMode, guestUserTokenizationEnabled);
paymentsRequest.setShopperInteraction(PaymentsRequest.ShopperInteractionEnum.ECOMMERCE);
if (BooleanUtils.isTrue(SubscriptionsUtils.containsSubscription(getCartFacade().getSessionCart()))) {
paymentsRequest.setRecurringProcessingModel(PaymentsRequest.RecurringProcessingModelEnum.SUBSCRIPTION);
} else {
paymentsRequest.setRecurringProcessingModel(PaymentsRequest.RecurringProcessingModelEnum.CARDONFILE);
public PaymentsRequest createPaymentsRequest(String merchantAccount, CartData cartData, RequestInfo requestInfo,
CustomerModel customerModel, RecurringContractMode recurringContractMode,
Boolean guestUserTokenizationEnabled) {

LOG.info("Creating PaymentsRequest for merchant account: {}", merchantAccount);

if (BooleanUtils.isTrue(cartData.getSubscriptionOrder())) {
return createRecurringPaymentsRequest(merchantAccount, cartData, requestInfo, customerModel,
recurringContractMode, guestUserTokenizationEnabled);
}

return createRegularPaymentsRequest(merchantAccount, cartData, requestInfo, customerModel,
recurringContractMode, guestUserTokenizationEnabled);
}

private PaymentsRequest createRegularPaymentsRequest(String merchantAccount, CartData cartData, RequestInfo requestInfo,
CustomerModel customerModel, RecurringContractMode recurringContractMode,
Boolean guestUserTokenizationEnabled) {
LOG.info("Creating regular PaymentsRequest...");
PaymentsRequest paymentsRequest = super.createPaymentsRequest(merchantAccount, cartData, requestInfo,
customerModel, recurringContractMode, guestUserTokenizationEnabled);
paymentsRequest.setShopperInteraction(PaymentsRequest.ShopperInteractionEnum.CONTAUTH);

PaymentsRequest.RecurringProcessingModelEnum recurringProcessingModel = BooleanUtils.isTrue(
SubscriptionsUtils.containsSubscription(getCartFacade().getSessionCart()))
? PaymentsRequest.RecurringProcessingModelEnum.SUBSCRIPTION
: PaymentsRequest.RecurringProcessingModelEnum.CARDONFILE;

paymentsRequest.setRecurringProcessingModel(recurringProcessingModel);
return paymentsRequest;
}

protected PaymentsRequest createRecurringPaymentsRequest(final String merchantAccount, final CartData cartData,
final RequestInfo requestInfo, final CustomerModel customerModel, final RecurringContractMode recurringContractMode,
final Boolean guestUserTokenizationEnabled)
{

LOG.info("Creating RecurringPaymentsRequest for merchant account: {}", merchantAccount);

final PaymentsRequest paymentsRequest = new PaymentsRequest();
final String adyenPaymentMethod = cartData.getAdyenPaymentMethod();

if (adyenPaymentMethod == null)
{
throw new IllegalArgumentException("Payment method is null");
}

updatePaymentRequest(merchantAccount, cartData, requestInfo, customerModel, paymentsRequest);

final PaymentMethodDetails paymentMethod = adyenPaymentMethodDetailsBuilderExecutor.createPaymentMethodDetails(cartData);
if(paymentMethod instanceof CardDetails) {
((CardDetails) paymentMethod).setStoredPaymentMethodId(cartData.getAdyenSelectedReference());
}
paymentMethod.setType(Adyenv6coreConstants.PAYMENT_METHOD_SCHEME);
paymentsRequest.setPaymentMethod(paymentMethod);


updateApplicationInfoEcom(paymentsRequest.getApplicationInfo());


paymentsRequest.setRedirectFromIssuerMethod(RequestMethod.POST.toString());
paymentsRequest.setRedirectToIssuerMethod(RequestMethod.POST.toString());
paymentsRequest.setShopperInteraction(PaymentsRequest.ShopperInteractionEnum.CONTAUTH);
paymentsRequest.setRecurringProcessingModel(PaymentsRequest.RecurringProcessingModelEnum.SUBSCRIPTION);

return paymentsRequest;
}


private void updatePaymentRequest(final String merchantAccount, final CartData cartData, final RequestInfo requestInfo,
final CustomerModel customerModel, final PaymentsRequest paymentsRequest)
{


final String currency = cartData.getTotalPrice().getCurrencyIso();
final String reference = cartData.getCode();

final AddressData billingAddress = cartData.getPaymentInfo() != null ? cartData.getPaymentInfo().getBillingAddress() : null;
final AddressData deliveryAddress = cartData.getDeliveryAddress();

paymentsRequest.amount(Util.createAmount(cartData.getTotalPrice().getValue(), currency)).reference(reference).merchantAccount(merchantAccount)
.setCountryCode(getCountryCode(cartData));
// set shopper details from CustomerModel.
if (customerModel != null)
{
paymentsRequest.setShopperReference(customerModel.getCustomerID());
paymentsRequest.setShopperEmail(customerModel.getContactEmail());
}

// if address details are provided, set it to the PaymentRequest
if (deliveryAddress != null)
{
paymentsRequest.setDeliveryAddress(setAddressData(deliveryAddress));
}

if (billingAddress != null)
{
paymentsRequest.setBillingAddress(setAddressData(billingAddress));
// set PhoneNumber if it is provided
final String phone = billingAddress.getPhone();
if (phone != null && !phone.isEmpty())
{
paymentsRequest.setTelephoneNumber(phone);
}
}

}

@Override
public RecurringDetailsRequest createListRecurringDetailsRequest(String merchantAccount, String customerId) {
if (SubscriptionsUtils.containsSubscription(getCartFacade().getSessionCart())) {
Expand All @@ -52,6 +150,7 @@ public RecurringDetailsRequest createListRecurringDetailsRequest(String merchant
}



protected CartFacade getCartFacade() {
return cartFacade;
}
Expand Down
Loading

0 comments on commit 2589085

Please sign in to comment.