package com.paymill.services; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang3.time.DateUtils; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import com.paymill.context.PaymillContext; import com.paymill.models.Client; import com.paymill.models.Interval; import com.paymill.models.Offer; import com.paymill.models.Payment; import com.paymill.models.Subscription; import com.paymill.utils.HttpClient; import com.paymill.utils.JerseyClient; public class SubscriptionServiceTest { private Date inAWeek = DateUtils.addWeeks( new Date(), 1 ); private Date inTwoWeeks = DateUtils.addWeeks( new Date(), 2 ); private Date inAMonth = DateUtils.addMonths( new Date(), 1 ); private SubscriptionService subscriptionService; private PaymentService paymentService; private ClientService clientService; private OfferService offerService; private String clientEmail = "john.rambo@qaiware.com"; private String clientDescription = "Boom, boom, shake the room"; private String token = "098f6bcd4621d373cade4e832627b4f6"; private Integer amount = 900; private String currency = "EUR"; private Interval.Period interval = Interval.period( 1, Interval.Unit.MONTH ); private String name = "Chuck Testa"; private Client client; private Payment payment; private Offer offer1; private Offer offer2; private Offer offer3; private Offer offer4; private Offer offer5; private List<Subscription> subscriptions; @BeforeClass public void setUp() { PaymillContext paymill = new PaymillContext( System.getProperty( "privateKey" ) ); this.subscriptionService = paymill.getSubscriptionService(); this.paymentService = paymill.getPaymentService(); this.clientService = paymill.getClientService(); this.offerService = paymill.getOfferService(); this.client = this.clientService.createWithEmailAndDescription( this.clientEmail, this.clientDescription ); this.offer1 = this.offerService.create( this.amount, this.currency, this.interval, this.name ); this.offer2 = this.offerService.create( this.amount * 2, this.currency, this.interval, "Updated " + this.name ); this.offer3 = this.offerService.create( this.amount * 3, this.currency, this.interval, "Updated " + this.name ); this.offer4 = this.offerService.create( this.amount * 4, this.currency, this.interval, "SubsOffer4" ); this.offer5 = this.offerService.create( this.amount * 6, this.currency, this.interval, "SubsOffer5" ); this.subscriptions = new ArrayList<Subscription>(); } @BeforeMethod public void setToken() { HttpClient httpClient = new JerseyClient( System.getProperty( "publicKey" ), 0 ); String content = httpClient.get( "https://test-token.paymill.com/?transaction.mode=CONNECTOR_TEST&channel.id=" + System.getProperty( "publicKey" ) + "&jsonPFunction=paymilljstests&account.number=4111111111111111&account.expiry.month=12&account.expiry.year=2015" + "&account.verification=123&account.holder=Max%20Mustermann&presentation.amount3D=2800&presentation.currency3D=EUR"); Pattern pattern = Pattern.compile( "(tok_)[a-z|0-9]+" ); Matcher matcher = pattern.matcher( content ); if( matcher.find() ) { this.token = matcher.group(); this.payment = this.paymentService.createWithTokenAndClient( this.token, this.client.getId() ); } } @AfterClass public void tearDown() { for( Subscription subscription : this.subscriptions ) { this.subscriptionService.delete( subscription ); } this.offerService.delete( offer1, true ); this.offerService.delete( offer2, true ); this.offerService.delete( offer3, true ); this.offerService.delete( offer4, true ); this.offerService.delete( offer5, true ); } @Test public void testCreateWithPaymentAndOffer() { Subscription subscription = this.subscriptionService.create( Subscription.create( this.payment, this.offer3 ) ); Assert.assertNotNull( subscription ); Assert.assertNotNull( subscription.getClient() ); Assert.assertEquals( subscription.getPayment().getId(), this.payment.getId() ); Assert.assertEquals( subscription.getOffer().getId(), this.offer3.getId() ); this.subscriptions.add( subscription ); } @Test public void testCreateWithPaymentAndOfferComplex() { Date tomorrow = DateUtils.addDays( new Date(), 1 ); Subscription subscription = this.subscriptionService.create( Subscription.create( this.payment, this.offer1 ).withClient( this.client ) .withAmount( this.amount * 5 ).withCurrency( "EUR" ).withInterval( "2 WEEK,monday" ).withName( "test sub" ).withOffer( this.offer2 ) .withPeriodOfValidity( "1 YEAR" ).withStartDate( tomorrow ) ); Assert.assertNotNull( subscription ); Assert.assertNotNull( subscription.getClient() ); Assert.assertEquals( subscription.getPayment().getId(), this.payment.getId() ); Assert.assertEquals( subscription.getClient().getId(), this.client.getId() ); Assert.assertEquals( subscription.getAmount(), (Integer) (this.amount * 5) ); Assert.assertEquals( subscription.getCurrency(), "EUR" ); Assert.assertEquals( subscription.getInterval().getInterval(), (Integer) 2 ); Assert.assertEquals( subscription.getInterval().getUnit(), Interval.Unit.WEEK ); Assert.assertEquals( subscription.getInterval().getWeekday(), Interval.Weekday.MONDAY ); Assert.assertEquals( subscription.getName(), "test sub" ); Assert.assertEquals( subscription.getPeriodOfValidity().getInterval(), (Integer) 1 ); Assert.assertEquals( subscription.getPeriodOfValidity().getUnit(), Interval.Unit.YEAR ); Assert.assertTrue( subscription.getNextCaptureAt().getTime() > new Date().getTime() ); Assert.assertEquals( subscription.getStatus(), Subscription.Status.ACTIVE ); Assert.assertFalse( subscription.getCanceled() ); Assert.assertFalse( subscription.getCanceled() ); Assert.assertFalse( subscription.getLivemode() ); Assert.assertNull( subscription.getCanceledAt() ); Assert.assertTrue( datesAroundSame( subscription.getCreatedAt(), new Date() ) ); Assert.assertTrue( datesAroundSame( subscription.getTrialStart(), new Date() ) ); Assert.assertTrue( datesAroundSame( subscription.getTrialEnd(), tomorrow ) ); Assert.assertTrue( datesAroundSame( subscription.getNextCaptureAt(), tomorrow ) ); Assert.assertNull( subscription.getTempAmount() ); this.subscriptions.add( subscription ); } @Test( expectedExceptions = IllegalArgumentException.class ) public void testCreateWithoutOfferAndAmount_shouldFail() { this.subscriptionService.create( this.payment, this.client, null, null, null, null, null, null, null ); } @Test public void testCreateWithPaymentAndClient_WithOfferWithoutTrial_shouldReturnSubscriptionWithNullTrialStartAndNullTrialEnd() { Client client = clientService.createWithEmail( "zendest@example.com" ); Payment payment = paymentService.createWithTokenAndClient( "098f6bcd4621d373cade4e832627b4f6", client ); Offer offer = offerService.create( 2223, "EUR", Interval.period( 1, Interval.Unit.WEEK ), "Offer No Trial" ); Subscription subscriptionNoTrial = subscriptionService.create( Subscription.create( payment.getId(), offer ).withClient( client.getId() ) ); Assert.assertNull( subscriptionNoTrial.getTrialStart() ); Assert.assertNull( subscriptionNoTrial.getTrialEnd() ); this.subscriptions.add( subscriptionNoTrial ); } @Test public void testCreateWithPaymentAndClient_WithOfferWithTrial_shouldReturnSubscriptionWithTrialEqualsTrialInOffer() { Client client = clientService.createWithEmail( "zendest@example.com" ); Payment payment = paymentService.createWithTokenAndClient( "098f6bcd4621d373cade4e832627b4f6", client ); Offer offer = offerService.create( 2225, "EUR", Interval.period( 1, Interval.Unit.WEEK ), "Offer With Trial", 2 ); Subscription subscriptionWithOfferTrial = subscriptionService.create( Subscription.create( payment.getId(), offer ).withClient( client.getId() ) ); Assert.assertNotNull( subscriptionWithOfferTrial.getTrialStart() ); Assert.assertTrue( datesAroundSame( subscriptionWithOfferTrial.getTrialEnd(), DateUtils.addDays( new Date(), 2 ) ) ); Assert.assertTrue( datesAroundSame( subscriptionWithOfferTrial.getNextCaptureAt(), DateUtils.addDays( new Date(), 2 ) ) ); this.subscriptions.add( subscriptionWithOfferTrial ); } @Test public void testCreateWithPaymentClientAndStartat_WithOfferWithTrial_shouldReturnSubscriptionWithTrialEqualsTrialInSubscription() { Client client = clientService.createWithEmail( "zendest@example.com" ); Payment payment = paymentService.createWithTokenAndClient( "098f6bcd4621d373cade4e832627b4f6", client ); Offer offer = offerService.create( 2224, "EUR", Interval.period( 1, Interval.Unit.WEEK ), "Offer No Trial", 2 ); Subscription subscriptionWithOfferTrial = subscriptionService.create( Subscription.create( payment.getId(), offer ).withClient( client.getId() ) .withStartDate( DateUtils.addDays( new Date(), 5 ) ) ); Assert.assertNotNull( subscriptionWithOfferTrial.getTrialStart() ); Assert.assertTrue( datesAroundSame( subscriptionWithOfferTrial.getTrialEnd(), DateUtils.addDays( new Date(), 5 ) ) ); Assert.assertTrue( datesAroundSame( subscriptionWithOfferTrial.getNextCaptureAt(), DateUtils.addDays( new Date(), 5 ) ) ); this.subscriptions.add( subscriptionWithOfferTrial ); } @Test public void testPauseAndUnpauseSubscription() { Subscription subscription = subscriptionService.create( Subscription.create( this.payment, 1200, "EUR", "1 WEEK" ) ); subscriptionService.pause( subscription ); Assert.assertEquals( subscription.getStatus(), Subscription.Status.INACTIVE ); subscriptionService.unpause( subscription ); Assert.assertEquals( subscription.getStatus(), Subscription.Status.ACTIVE ); Assert.assertTrue( datesAroundSame( subscription.getNextCaptureAt(), DateUtils.addWeeks( new Date(), 1 ) ) ); this.subscriptions.add( subscription ); } @Test public void testChangeSubscriptionAmountPermanently() { Subscription subscription = subscriptionService.create( Subscription.create( this.payment, 1200, "EUR", "1 WEEK" ) ); subscriptionService.changeAmount( subscription, 2000 ); Assert.assertEquals( subscription.getAmount(), (Integer) 2000 ); Assert.assertNull( subscription.getTempAmount() ); this.subscriptions.add( subscription ); } @Test public void testChangeSubscriptionAmountTemp() { Subscription subscription = subscriptionService.create( Subscription.create( this.payment, 1200, "EUR", "1 WEEK" ) ); subscriptionService.changeAmountTemporary( subscription, 2000 ); Assert.assertEquals( subscription.getAmount(), (Integer) 1200 ); Assert.assertEquals( subscription.getTempAmount(), (Integer) 2000 ); this.subscriptions.add( subscription ); } @Test public void testChangeOfferKeepNextCaptureNoRefund() { Subscription subscription = subscriptionService.create( Subscription.create( this.payment, 1200, "EUR", "1 WEEK" ) ); Assert.assertTrue( datesAroundSame( subscription.getNextCaptureAt(), inAWeek ) ); subscriptionService.changeOfferKeepCaptureDateNoRefund( subscription, this.offer1 ); Assert.assertTrue( datesAroundSame( subscription.getNextCaptureAt(), inAWeek ) ); this.subscriptions.add( subscription ); } @Test public void testChangeOfferKeepNextCaptureAndRefund() { Subscription subscription = subscriptionService.create( Subscription.create( this.payment, 1200, "EUR", "1 WEEK" ) ); Assert.assertTrue( datesAroundSame( subscription.getNextCaptureAt(), inAWeek ) ); subscriptionService.changeOfferKeepCaptureDateAndRefund( subscription, this.offer1 ); //TODO cannot be tested correctly as there //Assert.assertTrue( datesAroundSame( subscription.getNextCaptureAt(), inAWeek ) ); this.subscriptions.add( subscription ); } @Test public void testChangeOfferChangeNextCaptureAndRefund() { Subscription subscription = subscriptionService.create( Subscription.create( this.payment, 1200, "EUR", "1 WEEK" ).withStartDate( inTwoWeeks ) ); Assert.assertTrue( datesAroundSame( subscription.getNextCaptureAt(), inTwoWeeks ) ); subscriptionService.changeOfferChangeCaptureDateAndRefund( subscription, this.offer1 ); //TODO track this // when we call the above we trigger a transaction, so the nextCapture moves to offer1 interval - 1 month //Assert.assertTrue( datesAroundSame( subscription.getNextCaptureAt(), inAMonth ) ); this.subscriptions.add( subscription ); } @Test public void testEndTrial() { Subscription subscription = subscriptionService.create( Subscription.create( this.payment, 1200, "EUR", "1 WEEK" ).withStartDate( inTwoWeeks ) ); Assert.assertTrue( datesAroundSame( subscription.getNextCaptureAt(), inTwoWeeks ) ); subscriptionService.endTrial( subscription ); Assert.assertTrue( datesAroundSame( subscription.getNextCaptureAt(), new Date() ) ); Assert.assertNull( subscription.getTrialStart() ); this.subscriptions.add( subscription ); } @Test public void testEndTrialOnDate() { Subscription subscription = subscriptionService.create( Subscription.create( this.payment, 1200, "EUR", "1 WEEK" ).withStartDate( inTwoWeeks ) ); Assert.assertTrue( datesAroundSame( subscription.getNextCaptureAt(), inTwoWeeks ) ); subscriptionService.endTrialAt( subscription, inAMonth ); Assert.assertNotNull( subscription.getTrialEnd() ); Assert.assertTrue( datesAroundSame( subscription.getTrialEnd(), inAMonth ) ); this.subscriptions.add( subscription ); } @Test public void testChangePeriodValidity() { Subscription subscription = subscriptionService.create( Subscription.create( this.payment, 1200, "EUR", "2 MONTH" ).withPeriodOfValidity( "1 YEAR" ) ); Assert.assertEquals( subscription.getPeriodOfValidity().getInterval(), (Integer) 1 ); Assert.assertEquals( subscription.getPeriodOfValidity().getUnit(), Interval.Unit.YEAR ); subscriptionService.limitValidity( subscription, "2 MONTH" ); Assert.assertEquals( subscription.getPeriodOfValidity().getInterval(), (Integer) 2 ); Assert.assertEquals( subscription.getPeriodOfValidity().getUnit(), Interval.Unit.MONTH ); subscriptionService.unlimitValidity( subscription ); Assert.assertNull( subscription.getPeriodOfValidity() ); this.subscriptions.add( subscription ); } @Test public void testCancelSubscription() throws InterruptedException { Subscription subscription = subscriptionService.create( Subscription.create( this.payment, 1200, "EUR", "1 WEEK" ).withInterval( "1 WEEK" ) ); subscriptionService.cancel( subscription ); //TODO this seems to be an API bug, as the subscription is not updated immediately. we "refresh" Assert.assertEquals( subscription.getStatus(), Subscription.Status.INACTIVE ); Assert.assertEquals( subscription.getCanceled(), Boolean.TRUE ); Assert.assertEquals( subscription.getDeleted(), Boolean.FALSE ); this.subscriptions.add( subscription ); } @Test public void testDeleteSubscription() throws InterruptedException { Subscription subscription = subscriptionService.create( Subscription.create( this.payment, 1200, "EUR", "1 WEEK" ).withInterval( "1 WEEK" ) ); subscriptionService.delete( subscription ); //TODO this seems to be an API bug, as the subscription is not updated immediately. we "refresh" Assert.assertEquals( subscription.getStatus(), Subscription.Status.INACTIVE ); Assert.assertEquals( subscription.getCanceled(), Boolean.TRUE ); Assert.assertEquals( subscription.getDeleted(), Boolean.TRUE ); } @Test public void testUpdateSubscription() { Subscription subscription = subscriptionService.create( Subscription.create( this.payment, 2000, "EUR", "1 WEEK" ).withName( "test1" ) ); subscription.setCurrency( "USD" ); subscription.setInterval( Interval.periodWithChargeDay( 2, Interval.Unit.MONTH ) ); subscription.setName( "test2" ); subscriptionService.update( subscription ); Assert.assertEquals( subscription.getCurrency(), "USD" ); Assert.assertEquals( subscription.getInterval().getInterval(), (Integer) 2 ); Assert.assertEquals( subscription.getInterval().getUnit(), Interval.Unit.MONTH ); Assert.assertEquals( subscription.getName(), "test2" ); } @Test( dependsOnMethods = "testCreateWithPaymentAndOfferComplex" ) public void testListOrderByCreatedAsc() { Subscription.Order order = Subscription.createOrder().byCreatedAt().asc(); List<Subscription> subscriptions = this.subscriptionService.list( null, order ).getData(); for( int i = 1; i < subscriptions.size(); i++ ) { subscriptions.get( i ).getCreatedAt().after( subscriptions.get( i - 1 ).getCreatedAt() ); } } @Test( dependsOnMethods = "testCreateWithPaymentAndOfferComplex" ) public void testListOrderByCreatedDesc() { Subscription.Order order = Subscription.createOrder().byCreatedAt().desc(); List<Subscription> subscriptions = this.subscriptionService.list( null, order ).getData(); for( int i = 1; i < subscriptions.size(); i++ ) { subscriptions.get( i ).getCreatedAt().before( subscriptions.get( i - 1 ).getCreatedAt() ); } } public static boolean datesAroundSame( Date first, Date second, int minutes ) { long timespan = minutes * 60 * 1000; return Math.abs( first.getTime() - second.getTime() ) < timespan; } public static boolean datesAroundSame( Date first, Date second ) { return datesAroundSame( first, second, 10 ); } }