예제 #1
0
func createSubItem(t *testing.T) (*stripe.Sub, *stripe.SubItem, func()) {
	customerParams := &stripe.CustomerParams{
		Source: &stripe.SourceParams{
			Card: &stripe.CardParams{
				Number: "378282246310005",
				Month:  "06",
				Year:   "20",
			},
		},
	}

	cust, err := customer.New(customerParams)
	if err != nil {
		t.Fatalf("customer creation: %s", err)
	}

	planID := fmt.Sprintf("test-%d", rand.Int63())
	planParams := &stripe.PlanParams{
		ID:       planID,
		Name:     "Test Plan",
		Amount:   99,
		Currency: currency.USD,
		Interval: plan.Month,
	}

	p, err := plan.New(planParams)
	if err != nil {
		t.Fatalf("plan creation: %s", err)
	}

	subParams := &stripe.SubParams{
		Customer: cust.ID,
		Items: []*stripe.SubItemsParams{
			{
				Plan:     p.ID,
				Quantity: 1,
			},
		},
	}

	target, err := sub.New(subParams)
	if err != nil {
		t.Fatalf("subscription creation: %s", err)
	}
	if target.Items == nil {
		t.Fatalf("no items for sub %s", target.ID)
	}
	if len(target.Items.Values) != 1 {
		t.Fatalf("missing items: %#v", target)
	}
	return target, target.Items.Values[0], func() {
		sub.Cancel(target.ID, nil)
		plan.Del(p.ID)
		customer.Del(cust.ID)
	}
}
예제 #2
0
func TestSubscriptionNew(t *testing.T) {
	customerParams := &stripe.CustomerParams{
		Source: &stripe.SourceParams{
			Card: &stripe.CardParams{
				Number: "378282246310005",
				Month:  "06",
				Year:   "20",
			},
		},
	}

	cust, _ := customer.New(customerParams)

	planParams := &stripe.PlanParams{
		ID:       "test",
		Name:     "Test Plan",
		Amount:   99,
		Currency: currency.USD,
		Interval: plan.Month,
	}

	plan.New(planParams)

	subParams := &stripe.SubParams{
		Customer:           cust.ID,
		Plan:               "test",
		Quantity:           10,
		TaxPercent:         20.0,
		BillingCycleAnchor: time.Now().AddDate(0, 0, 12).Unix(),
	}

	target, err := New(subParams)

	if err != nil {
		t.Error(err)
	}

	if target.Plan.ID != subParams.Plan {
		t.Errorf("Plan %v does not match expected plan %v\n", target.Plan, subParams.Plan)
	}

	if target.Quantity != subParams.Quantity {
		t.Errorf("Quantity %v does not match expected quantity %v\n", target.Quantity, subParams.Quantity)
	}

	if target.TaxPercent != subParams.TaxPercent {
		t.Errorf("TaxPercent %f does not match expected TaxPercent %f\n", target.TaxPercent, subParams.TaxPercent)
	}

	if target.PeriodEnd != subParams.BillingCycleAnchor {
		t.Errorf("PeriodEnd %v does not match expected BillingCycleAnchor %v\n", target.PeriodEnd, subParams.BillingCycleAnchor)
	}

	customer.Del(cust.ID)
	plan.Del("test")
}
예제 #3
0
func TestSubscriptionUpdate(t *testing.T) {
	customerParams := &stripe.CustomerParams{
		Source: &stripe.SourceParams{
			Card: &stripe.CardParams{
				Number: "378282246310005",
				Month:  "06",
				Year:   "20",
			},
		},
	}

	cust, _ := customer.New(customerParams)

	planParams := &stripe.PlanParams{
		ID:       "test",
		Name:     "Test Plan",
		Amount:   99,
		Currency: currency.USD,
		Interval: plan.Month,
	}

	plan.New(planParams)

	subParams := &stripe.SubParams{
		Customer:    cust.ID,
		Plan:        "test",
		Quantity:    10,
		TrialEndNow: true,
	}

	subscription, _ := New(subParams)
	updatedSub := &stripe.SubParams{
		Customer:   cust.ID,
		NoProrate:  true,
		Quantity:   13,
		TaxPercent: 20.0,
	}

	target, err := Update(subscription.ID, updatedSub)

	if err != nil {
		t.Error(err)
	}

	if target.Quantity != updatedSub.Quantity {
		t.Errorf("Quantity %v does not match expected quantity %v\n", target.Quantity, updatedSub.Quantity)
	}

	if target.TaxPercent != updatedSub.TaxPercent {
		t.Errorf("TaxPercent %f does not match expected tax_percent %f\n", target.TaxPercent, updatedSub.TaxPercent)
	}

	customer.Del(cust.ID)
	plan.Del("test")
}
예제 #4
0
func TestSubscriptionCancel(t *testing.T) {
	customerParams := &stripe.CustomerParams{
		Source: &stripe.SourceParams{
			Card: &stripe.CardParams{
				Number: "378282246310005",
				Month:  "06",
				Year:   "20",
			},
		},
	}

	cust, _ := customer.New(customerParams)

	planParams := &stripe.PlanParams{
		ID:       "test",
		Name:     "Test Plan",
		Amount:   99,
		Currency: currency.USD,
		Interval: plan.Month,
	}

	plan.New(planParams)

	subParams := &stripe.SubParams{
		Customer: cust.ID,
		Plan:     "test",
		Quantity: 10,
	}

	subscription, _ := New(subParams)
	s, err := Cancel(subscription.ID, nil)

	if err != nil {
		t.Error(err)
	}

	if s.Canceled == 0 {
		t.Errorf("Subscription.Canceled %v expected to be non 0\n", s.Canceled)
	}

	subscription, _ = New(subParams)
	s, err = Cancel(subscription.ID, &stripe.SubParams{Customer: cust.ID})

	if err != nil {
		t.Error(err)
	}

	if s.Canceled == 0 {
		t.Errorf("Subscription.Canceled %v expected to be non 0\n", s.Canceled)
	}

	customer.Del(cust.ID)
	plan.Del("test")
}
예제 #5
0
// make sure we can subscribe to 7 days-free plan with more trial period
func TestSubscribingToPaidPlanWithWithDifferentTrialPeriodThanDefault(t *testing.T) {
	Convey("Given stub data", t, func() {
		withTestServer(t, func(endpoint string) {
			withStubData(endpoint, func(username, groupName, sessionID string) {
				pp := &stripe.PlanParams{
					Amount:        12345,
					Interval:      stripeplan.Month,
					IntervalCount: 1,
					TrialPeriod:   1, // trial for one day
					Name:          fmt.Sprintf("plan for %s", username),
					Currency:      currency.USD,
					ID:            fmt.Sprintf("plan_for_%s", username),
					Statement:     "NAN-FREE",
				}

				plan, err := stripeplan.New(pp)
				So(err, ShouldBeNil)

				addCreditCardToUserWithChecks(endpoint, sessionID)

				createURL := endpoint + EndpointSubscriptionCreate
				deleteURL := endpoint + EndpointSubscriptionCancel
				group, err := modelhelper.GetGroup(groupName)
				tests.ResultedWithNoErrorCheck(group, err)

				req, err := json.Marshal(&stripe.SubParams{
					Customer: group.Payment.Customer.ID,
					Plan:     plan.ID,
					TrialEnd: time.Now().Add(time.Hour * 48).Unix(),
				})
				tests.ResultedWithNoErrorCheck(req, err)

				sub, err := rest.DoRequestWithAuth("POST", createURL, req, sessionID)
				tests.ResultedWithNoErrorCheck(sub, err)

				v := &stripe.Sub{}
				err = json.Unmarshal(sub, v)
				So(err, ShouldBeNil)

				So(v.TrialEnd, ShouldBeGreaterThan, time.Now().Add(time.Hour*24*time.Duration(pp.TrialPeriod)).Unix())

				Convey("We should be able to cancel the subscription", func() {
					res, err := rest.DoRequestWithAuth("DELETE", deleteURL, req, sessionID)
					tests.ResultedWithNoErrorCheck(res, err)

					v := &stripe.Sub{}
					err = json.Unmarshal(res, v)
					So(err, ShouldBeNil)
					So(v.Status, ShouldEqual, "canceled")
				})
			})
		})
	})
}
예제 #6
0
func TestSubscriptionGet(t *testing.T) {
	customerParams := &stripe.CustomerParams{
		Source: &stripe.SourceParams{
			Card: &stripe.CardParams{
				Number: "378282246310005",
				Month:  "06",
				Year:   "20",
			},
		},
	}

	cust, _ := customer.New(customerParams)

	planParams := &stripe.PlanParams{
		ID:       "test",
		Name:     "Test Plan",
		Amount:   99,
		Currency: currency.USD,
		Interval: plan.Month,
	}

	plan.New(planParams)

	subParams := &stripe.SubParams{
		Customer: cust.ID,
		Plan:     "test",
		Quantity: 10,
	}

	subscription, _ := New(subParams)
	target, err := Get(subscription.ID, nil)

	if err != nil {
		t.Error(err)
	}

	if target.ID != subscription.ID {
		t.Errorf("Subscription id %q does not match expected id %q\n", target.ID, subscription.ID)
	}

	target, err = Get(subscription.ID, &stripe.SubParams{Customer: cust.ID})

	if err != nil {
		t.Error(err)
	}

	if target.ID != subscription.ID {
		t.Errorf("Subscription id %q does not match expected id %q\n", target.ID, subscription.ID)
	}

	customer.Del(cust.ID)
	plan.Del("test")
}
예제 #7
0
func TestSubscriptionZeroQuantity(t *testing.T) {
	customerParams := &stripe.CustomerParams{
		Source: &stripe.SourceParams{
			Card: &stripe.CardParams{
				Number: "378282246310005",
				Month:  "06",
				Year:   "20",
			},
		},
	}

	cust, _ := customer.New(customerParams)

	planParams := &stripe.PlanParams{
		ID:       "test",
		Name:     "Test Plan",
		Amount:   99,
		Currency: currency.USD,
		Interval: plan.Month,
	}

	plan.New(planParams)

	subParams := &stripe.SubParams{
		Customer:       cust.ID,
		Plan:           "test",
		QuantityZero:   true,
		TaxPercentZero: true,
	}

	target, err := New(subParams)

	if err != nil {
		t.Error(err)
	}

	if target.Plan.ID != subParams.Plan {
		t.Errorf("Plan %v does not match expected plan %v\n", target.Plan, subParams.Plan)
	}

	if target.Quantity != 0 {
		t.Errorf("Quantity %v does not match expected quantity %v\n", target.Quantity, 0)
	}

	if target.TaxPercent != 0 {
		t.Errorf("Tax percent %v does not match expected tax percent %v\n", target.TaxPercent, 0)
	}

	customer.Del(cust.ID)
	plan.Del("test")
}
예제 #8
0
func TestSubscriptionList(t *testing.T) {
	customerParams := &stripe.CustomerParams{
		Source: &stripe.SourceParams{
			Card: &stripe.CardParams{
				Number: "378282246310005",
				Month:  "06",
				Year:   "20",
			},
		},
	}

	cust, _ := customer.New(customerParams)

	planParams := &stripe.PlanParams{
		ID:       "test",
		Name:     "Test Plan",
		Amount:   99,
		Currency: currency.USD,
		Interval: plan.Month,
	}

	plan.New(planParams)

	subParams := &stripe.SubParams{
		Customer: cust.ID,
		Plan:     "test",
		Quantity: 10,
	}

	for i := 0; i < 5; i++ {
		New(subParams)
	}

	i := List(&stripe.SubListParams{Customer: cust.ID})
	for i.Next() {
		if i.Sub() == nil {
			t.Error("No nil values expected")
		}

		if i.Meta() == nil {
			t.Error("No metadata returned")
		}
	}
	if err := i.Err(); err != nil {
		t.Error(err)
	}

	customer.Del(cust.ID)
	plan.Del("test")
}
예제 #9
0
// EnsurePlan makes sure plan is in stripe
func EnsurePlan(planParams *stripe.PlanParams) error {
	p, err := stripeplan.Get(planParams.ID, nil)
	if err == nil && p != nil && p.ID == planParams.ID {
		return nil
	}

	stripeErr, ok := err.(*stripe.Error)
	if !ok {
		return err
	}

	if stripeErr.Type != stripe.ErrorTypeInvalidRequest {
		return err
	}

	_, err = stripeplan.New(planParams)
	return err
}
예제 #10
0
func withTrialTestPlan(f func(planID string)) {
	pp := &stripe.PlanParams{
		Amount:        10,
		Interval:      plan.Month,
		IntervalCount: 1,
		TrialPeriod:   1,
		Name:          "Trailing 10",
		Currency:      currency.USD,
		ID:            fmt.Sprintf("p_%s", bson.NewObjectId().Hex()),
		Statement:     "Trailing 10",
	}

	_, err := plan.New(pp)
	So(err, ShouldBeNil)

	f(pp.ID)

	_, err = plan.Del(pp.ID)
	So(err, ShouldBeNil)
}
예제 #11
0
func withNonFreeTestPlan(f func(planID string)) {
	pp := &stripe.PlanParams{
		Amount:        12345,
		Interval:      plan.Month,
		IntervalCount: 1,
		TrialPeriod:   0,
		Name:          "If only that much free",
		Currency:      currency.USD,
		ID:            "p_" + bson.NewObjectId().Hex(),
		Statement:     "NAN-FREE",
	}

	_, err := plan.New(pp)
	So(err, ShouldBeNil)

	f(pp.ID)

	_, err = plan.Del(pp.ID)
	So(err, ShouldBeNil)
}
예제 #12
0
func TestListItems(t *testing.T) {
	sub, _, cleanup := createSubItem(t)
	defer cleanup()

	// Create a new plan
	planID := fmt.Sprintf("test-%d", rand.Int63())
	planParams := &stripe.PlanParams{
		ID:       planID,
		Name:     "Expensive plan",
		Amount:   1000,
		Currency: currency.USD,
		Interval: plan.Month,
	}
	p, err := plan.New(planParams)
	if err != nil {
		t.Fatal(err)
	}
	defer plan.Del(p.ID)

	item, err := New(&stripe.SubItemParams{
		Sub:      sub.ID,
		Plan:     p.ID,
		Quantity: 2,
	})
	if err != nil {
		t.Errorf("new err: %s", err)
	}
	if item.Quantity != 2 {
		t.Errorf("quantity should be 2 after update, not %d", item.Quantity)
	}

	if item.ID != "" {
		item, err := Del(item.ID, nil)
		if err != nil {
			t.Errorf("del err: %s", err)
		}
		if !item.Deleted {
			t.Errorf("item should be deleted %#v", item)
		}
	}
}
예제 #13
0
func TestCustomerNewWithPlan(t *testing.T) {
	planParams := &stripe.PlanParams{
		ID:       "test",
		Name:     "Test Plan",
		Amount:   99,
		Currency: currency.USD,
		Interval: plan.Month,
	}

	_, err := plan.New(planParams)
	if err != nil {
		t.Error(err)
	}

	customerParams := &stripe.CustomerParams{
		Plan:       planParams.ID,
		TaxPercent: 10.0,
	}
	customerParams.SetSource(&stripe.CardParams{
		Name:   "Test Card",
		Number: "378282246310005",
		Month:  "06",
		Year:   "20",
	})

	target, err := New(customerParams)

	if err != nil {
		t.Error(err)
	}

	_, err = Del(target.ID)
	if err != nil {
		t.Error(err)
	}

	_, err = plan.Del(planParams.ID)
	if err != nil {
		t.Error(err)
	}
}
예제 #14
0
func TestInvoiceCreatedHandlerDowngradePlan(t *testing.T) {
	testData := `
{
    "id": "in_00000000000000",
    "object": "invoice",
    "amount_due": 0,
    "application_fee": null,
    "attempt_count": 0,
    "attempted": false,
    "charge": null,
    "closed": false,
    "currency": "usd",
    "customer": "%s",
    "date": 1471348722,
    "description": null,
    "discount": null,
    "ending_balance": 0,
    "forgiven": false,
    "livemode": false,
    "metadata": {},
    "next_payment_attempt": null,
    "paid": false,
    "period_end": 1471348722,
    "period_start": 1471348722,
    "receipt_number": null,
    "starting_balance": 0,
    "statement_descriptor": null,
    "subscription": "%s",
    "subtotal": %d,
    "tax": null,
    "tax_percent": null,
    "total": %d,
    "webhooks_delivered_at": 1471348722
}`

	tests.WithConfiguration(t, func(c *config.Config) {
		stripe.Key = c.Stripe.SecretToken
		Convey("Given stub data", t, func() {
			withStubData(func(username, groupName, sessionID string) {
				group, err := modelhelper.GetGroup(groupName)
				tests.ResultedWithNoErrorCheck(group, err)

				withTestCreditCardToken(func(token string) {
					// attach payment source
					cp := &stripe.CustomerParams{
						Source: &stripe.SourceParams{
							Token: token,
						},
					}

					c, err := UpdateCustomerForGroup(username, groupName, cp)
					tests.ResultedWithNoErrorCheck(c, err)

					const totalMembers = 9
					generateAndAddMembersToGroup(group.Slug, totalMembers)

					// create test plan
					id := "p_" + bson.NewObjectId().Hex()
					pp := &stripe.PlanParams{
						Amount:        Plans[UpTo50Users].Amount,
						Interval:      plan.Month,
						IntervalCount: 1,
						TrialPeriod:   0,
						Name:          id,
						Currency:      currency.USD,
						ID:            id,
					}

					p, err := plan.New(pp)
					So(err, ShouldBeNil)

					// subscribe to test plan with more than actual number, simulating having 11 members previous month
					var extraneousCount uint64 = uint64(totalMembers) + 2
					params := &stripe.SubParams{
						Customer: group.Payment.Customer.ID,
						Plan:     p.ID,
						Quantity: extraneousCount,
					}

					sub, err := EnsureSubscriptionForGroup(group.Slug, params)
					tests.ResultedWithNoErrorCheck(sub, err)

					// check if group has correct sub id
					groupAfterSub, err := modelhelper.GetGroup(groupName)
					tests.ResultedWithNoErrorCheck(groupAfterSub, err)
					So(sub.ID, ShouldEqual, groupAfterSub.Payment.Subscription.ID)

					Convey("When invoice.created is triggered with previous plan's amount", func() {
						raw := []byte(fmt.Sprintf(
							testData,
							group.Payment.Customer.ID,
							sub.ID,
							Plans[UpTo10Users].Amount*extraneousCount,
							Plans[UpTo10Users].Amount*extraneousCount,
						))

						So(invoiceCreatedHandler(raw), ShouldBeNil)

						Convey("subscription id should not stay same", func() {
							groupAfterHook, err := modelhelper.GetGroup(groupName)
							tests.ResultedWithNoErrorCheck(groupAfterHook, err)

							// group should have correct sub id
							So(sub.ID, ShouldNotEqual, groupAfterHook.Payment.Subscription.ID)

							sub, err := GetSubscriptionForGroup(groupName)
							tests.ResultedWithNoErrorCheck(sub, err)

							So(sub.Plan.ID, ShouldEqual, UpTo10Users)

							count, err := (&models.PresenceDaily{}).CountDistinctByGroupName(group.Slug)
							So(err, ShouldBeNil)
							So(count, ShouldEqual, 0)

							Convey("we should clean up successfully", func() {
								sub, err := DeleteSubscriptionForGroup(group.Slug)
								tests.ResultedWithNoErrorCheck(sub, err)

								_, err = plan.Del(pp.ID)
								So(err, ShouldBeNil)
							})
						})
					})
				})
			})
		})
	})
}
예제 #15
0
func TestAtTheEndOfTrialPeriodSubscriptionStatusIsStillTrialing(t *testing.T) {
	Convey("Given stub data", t, func() {
		withTestServer(t, func(endpoint string) {
			withStubData(endpoint, func(username, groupName, sessionID string) {
				withTestCreditCardToken(func(token string) {
					req, err := json.Marshal(&stripe.CustomerParams{
						Source: &stripe.SourceParams{
							Token: token,
						},
					})
					tests.ResultedWithNoErrorCheck(req, err)

					res, err := rest.DoRequestWithAuth(
						"POST",
						endpoint+EndpointCustomerUpdate,
						req,
						sessionID,
					)
					tests.ResultedWithNoErrorCheck(res, err)

					createURL := endpoint + EndpointSubscriptionCreate
					group, err := modelhelper.GetGroup(groupName)
					tests.ResultedWithNoErrorCheck(group, err)

					pp := &stripe.PlanParams{
						Amount:        12345,
						Interval:      stripeplan.Month,
						IntervalCount: 1,
						TrialPeriod:   1, // trial for one day
						Name:          fmt.Sprintf("plan for %s", username),
						Currency:      currency.USD,
						ID:            fmt.Sprintf("plan_for_%s", username),
						Statement:     "NAN-FREE",
					}
					plan, err := stripeplan.New(pp)
					So(err, ShouldBeNil)
					defer stripeplan.Del(plan.ID)

					req, err = json.Marshal(&stripe.SubParams{
						Customer: group.Payment.Customer.ID,
						Plan:     plan.ID,
					})
					tests.ResultedWithNoErrorCheck(req, err)

					res, err = rest.DoRequestWithAuth("POST", createURL, req, sessionID)
					tests.ResultedWithNoErrorCheck(res, err)

					sub := &stripe.Sub{}
					err = json.Unmarshal(res, sub)
					So(err, ShouldBeNil)

					subParams := &stripe.SubParams{
						Customer: group.Payment.Customer.ID,
						Plan:     plan.ID,
						TrialEnd: time.Now().UTC().Add(time.Second * 60 * 5).Unix(),
					}
					sub, err = stripesub.Update(sub.ID, subParams)
					tests.ResultedWithNoErrorCheck(sub, err)

					sub, err = stripesub.Get(sub.ID, nil)
					tests.ResultedWithNoErrorCheck(sub, err)

					So(sub.Status, ShouldEqual, "trialing")
				})
			})
		})
	})
}
예제 #16
0
// Invoices are somewhat painful to test since you need
// to first have some items, so test everything together to
// avoid unnecessary duplication
func TestAllInvoicesScenarios(t *testing.T) {
	customerParams := &stripe.CustomerParams{
		Source: &stripe.SourceParams{
			Card: &stripe.CardParams{
				Number: "378282246310005",
				Month:  "06",
				Year:   "20",
			},
		},
	}

	cust, _ := customer.New(customerParams)

	item := &stripe.InvoiceItemParams{
		Customer: cust.ID,
		Amount:   100,
		Currency: currency.USD,
		Desc:     "Test Item",
	}

	targetItem, err := invoiceitem.New(item)

	if err != nil {
		t.Error(err)
	}

	if targetItem.Customer.ID != item.Customer {
		t.Errorf("Item customer %q does not match expected customer %q\n", targetItem.Customer.ID, item.Customer)
	}

	if targetItem.Desc != item.Desc {
		t.Errorf("Item description %q does not match expected description %q\n", targetItem.Desc, item.Desc)
	}

	if targetItem.Amount != item.Amount {
		t.Errorf("Item amount %v does not match expected amount %v\n", targetItem.Amount, item.Amount)
	}

	if targetItem.Currency != item.Currency {
		t.Errorf("Item currency %q does not match expected currency %q\n", targetItem.Currency, item.Currency)
	}

	if targetItem.Date == 0 {
		t.Errorf("Item date is not set\n")
	}

	invoiceParams := &stripe.InvoiceParams{
		Customer:   cust.ID,
		Desc:       "Desc",
		Statement:  "Statement",
		TaxPercent: 20.0,
	}

	targetInvoice, err := New(invoiceParams)

	if err != nil {
		t.Error(err)
	}

	if targetInvoice.Customer.ID != invoiceParams.Customer {
		t.Errorf("Invoice customer %q does not match expected customer %q\n", targetInvoice.Customer.ID, invoiceParams.Customer)
	}

	if targetInvoice.TaxPercent != invoiceParams.TaxPercent {
		t.Errorf("Invoice tax percent %f does not match expected tax percent %f\n", targetInvoice.TaxPercent, invoiceParams.TaxPercent)
	}

	if targetInvoice.Tax != 20 {
		t.Errorf("Invoice tax  %v does not match expected tax 20\n", targetInvoice.Tax)
	}

	if targetInvoice.Amount != targetItem.Amount+targetInvoice.Tax {
		t.Errorf("Invoice amount %v does not match expected amount %v + tax %v\n", targetInvoice.Amount, targetItem.Amount, targetInvoice.Tax)
	}

	if targetInvoice.Currency != targetItem.Currency {
		t.Errorf("Invoice currency %q does not match expected currency %q\n", targetInvoice.Currency, targetItem.Currency)
	}

	if targetInvoice.Date == 0 {
		t.Errorf("Invoice date is not set\n")
	}

	if targetInvoice.Start == 0 {
		t.Errorf("Invoice start is not set\n")
	}

	if targetInvoice.End == 0 {
		t.Errorf("Invoice end is not set\n")
	}

	if targetInvoice.Total != targetInvoice.Amount || targetInvoice.Subtotal != targetInvoice.Amount-targetInvoice.Tax {
		t.Errorf("Invoice total %v and subtotal %v do not match expected amount %v\n", targetInvoice.Total, targetInvoice.Subtotal, targetInvoice.Amount)
	}

	if targetInvoice.Desc != invoiceParams.Desc {
		t.Errorf("Invoice description %q does not match expected description %q\n", targetInvoice.Desc, invoiceParams.Desc)
	}

	if targetInvoice.Statement != invoiceParams.Statement {
		t.Errorf("Invoice statement %q does not match expected statement %q\n", targetInvoice.Statement, invoiceParams.Statement)
	}

	if targetInvoice.Lines == nil {
		t.Errorf("Invoice lines not found\n")
	}

	if targetInvoice.Lines.Count != 1 {
		t.Errorf("Invoice lines count %v does not match expected value\n", targetInvoice.Lines.Count)
	}

	if targetInvoice.Lines.Values == nil {
		t.Errorf("Invoice lines values not found\n")
	}

	if targetInvoice.Lines.Values[0].Amount != targetItem.Amount {
		t.Errorf("Invoice line amount %v does not match expected amount %v\n", targetInvoice.Lines.Values[0].Amount, targetItem.Amount)
	}

	if targetInvoice.Lines.Values[0].Currency != targetItem.Currency {
		t.Errorf("Invoice line currency %q does not match expected currency %q\n", targetInvoice.Lines.Values[0].Currency, targetItem.Currency)
	}

	if targetInvoice.Lines.Values[0].Desc != targetItem.Desc {
		t.Errorf("Invoice line description %q does not match expected description %q\n", targetInvoice.Lines.Values[0].Desc, targetItem.Desc)
	}

	if targetInvoice.Lines.Values[0].Type != TypeInvoiceItem {
		t.Errorf("Invoice line type %q does not match expected type\n", targetInvoice.Lines.Values[0].Type)
	}

	if targetInvoice.Lines.Values[0].Period == nil {
		t.Errorf("Invoice line period not found\n")
	}

	if targetInvoice.Lines.Values[0].Period.Start == 0 {
		t.Errorf("Invoice line period start is not set\n")
	}

	if targetInvoice.Lines.Values[0].Period.End == 0 {
		t.Errorf("Invoice line period end is not set\n")
	}

	updatedItem := &stripe.InvoiceItemParams{
		Amount:       99,
		Desc:         "Updated Desc",
		Discountable: true,
	}

	targetItemUpdated, err := invoiceitem.Update(targetItem.ID, updatedItem)

	if err != nil {
		t.Error(err)
	}

	if targetItemUpdated.Desc != updatedItem.Desc {
		t.Errorf("Updated item description %q does not match expected description %q\n", targetItemUpdated.Desc, updatedItem.Desc)
	}

	if targetItemUpdated.Amount != updatedItem.Amount {
		t.Errorf("Updated item amount %v does not match expected amount %v\n", targetItemUpdated.Amount, updatedItem.Amount)
	}

	if !targetItemUpdated.Discountable {
		t.Errorf("Updated item is not discountable")
	}

	updatedInvoice := &stripe.InvoiceParams{
		Desc:      "Updated Desc",
		Statement: "Updated",
	}

	targetInvoiceUpdated, err := Update(targetInvoice.ID, updatedInvoice)

	if err != nil {
		t.Error(err)
	}

	if targetInvoiceUpdated.Desc != updatedInvoice.Desc {
		t.Errorf("Updated invoice description %q does not match expected description %q\n", targetInvoiceUpdated.Desc, updatedInvoice.Desc)
	}

	if targetInvoiceUpdated.Statement != updatedInvoice.Statement {
		t.Errorf("Updated invoice statement %q does not match expected statement %q\n", targetInvoiceUpdated.Statement, updatedInvoice.Statement)
	}

	_, err = invoiceitem.Get(targetItem.ID, nil)
	if err != nil {
		t.Error(err)
	}

	ii := invoiceitem.List(&stripe.InvoiceItemListParams{Customer: cust.ID})
	for ii.Next() {
		if ii.InvoiceItem() == nil {
			t.Error("No nil values expected")
		}

		if ii.Meta() == nil {
			t.Error("No metadata returned")
		}
	}
	if err := ii.Err(); err != nil {
		t.Error(err)
	}

	i := List(&stripe.InvoiceListParams{Customer: cust.ID})
	for i.Next() {
		if i.Invoice() == nil {
			t.Error("No nil values expected")
		}

		if i.Meta() == nil {
			t.Error("No metadata returned")
		}
	}
	if err := i.Err(); err != nil {
		t.Error(err)
	}

	il := ListLines(&stripe.InvoiceLineListParams{ID: targetInvoice.ID, Customer: cust.ID})
	for il.Next() {
		if il.InvoiceLine() == nil {
			t.Error("No nil values expected")
		}

		if il.Meta() == nil {
			t.Error("No metadata returned")
		}
	}
	if err := il.Err(); err != nil {
		t.Error(err)
	}

	iiDel, err := invoiceitem.Del(targetItem.ID)

	if err != nil {
		t.Error(err)
	}

	if !iiDel.Deleted {
		t.Errorf("Invoice Item id %q expected to be marked as deleted on the returned resource\n", iiDel.ID)
	}

	_, err = Get(targetInvoice.ID, nil)

	if err != nil {
		t.Error(err)
	}

	planParams := &stripe.PlanParams{
		ID:       "test",
		Name:     "Test Plan",
		Amount:   99,
		Currency: currency.USD,
		Interval: plan.Month,
	}

	_, err = plan.New(planParams)
	if err != nil {
		t.Error(err)
	}

	subParams := &stripe.SubParams{
		Customer:    cust.ID,
		Plan:        planParams.ID,
		Quantity:    10,
		TrialEndNow: true,
	}

	subscription, err := sub.New(subParams)
	if err != nil {
		t.Error(err)
	}

	nextParams := &stripe.InvoiceParams{
		Customer:         cust.ID,
		Sub:              subscription.ID,
		SubPlan:          planParams.ID,
		SubNoProrate:     false,
		SubProrationDate: time.Now().AddDate(0, 0, 12).Unix(),
		SubQuantity:      1,
		SubTrialEnd:      time.Now().AddDate(0, 0, 12).Unix(),
	}

	nextInvoice, err := GetNext(nextParams)
	if err != nil {
		t.Error(err)
	}

	if nextInvoice.Customer.ID != cust.ID {
		t.Errorf("Invoice customer %v does not match expected customer%v\n", nextInvoice.Customer.ID, cust.ID)
	}

	if nextInvoice.Sub != subscription.ID {
		t.Errorf("Invoice subscription %v does not match expected subscription%v\n", nextInvoice.Sub, subscription.ID)
	}

	closeInvoice := &stripe.InvoiceParams{
		Closed: true,
	}

	targetInvoiceClosed, err := Update(targetInvoice.ID, closeInvoice)

	if err != nil {
		t.Error(err)
	}

	if targetInvoiceClosed.Closed != closeInvoice.Closed {
		t.Errorf("Invoice was not closed as expected and its value is %v", targetInvoiceClosed.Closed)
	}

	openInvoice := &stripe.InvoiceParams{
		NoClosed: true,
	}

	targetInvoiceOpened, err := Update(targetInvoice.ID, openInvoice)

	if err != nil {
		t.Error(err)
	}

	if targetInvoiceOpened.Closed != false {
		t.Errorf("Invoice was not reponed as expected and its value is %v", targetInvoiceOpened.Closed)
	}

	_, err = plan.Del(planParams.ID)
	if err != nil {
		t.Error(err)
	}

	customer.Del(cust.ID)
}
예제 #17
0
func TestSubscriptionDiscount(t *testing.T) {
	couponParams := &stripe.CouponParams{
		Duration: coupon.Forever,
		ID:       "sub_coupon",
		Percent:  99,
	}

	coupon.New(couponParams)

	customerParams := &stripe.CustomerParams{
		Source: &stripe.SourceParams{
			Card: &stripe.CardParams{
				Number: "378282246310005",
				Month:  "06",
				Year:   "20",
			},
		},
	}

	cust, _ := customer.New(customerParams)

	planParams := &stripe.PlanParams{
		ID:       "test",
		Name:     "Test Plan",
		Amount:   99,
		Currency: currency.USD,
		Interval: plan.Month,
	}

	plan.New(planParams)

	subParams := &stripe.SubParams{
		Customer: cust.ID,
		Plan:     "test",
		Quantity: 10,
		Coupon:   "sub_coupon",
	}

	target, err := New(subParams)

	if err != nil {
		t.Error(err)
	}

	if target.Discount == nil {
		t.Errorf("Discount not found, but one was expected\n")
	}

	if target.Discount.Coupon == nil {
		t.Errorf("Coupon not found, but one was expected\n")
	}

	if target.Discount.Coupon.ID != subParams.Coupon {
		t.Errorf("Coupon id %q does not match expected id %q\n", target.Discount.Coupon.ID, subParams.Coupon)
	}

	_, err = discount.DelSub(target.ID)

	if err != nil {
		t.Error(err)
	}

	target, err = Get(target.ID, nil)

	if err != nil {
		t.Error(err)
	}

	if target.Discount != nil {
		t.Errorf("A discount %v was found, but was expected to have been deleted\n", target.Discount)
	}

	customer.Del(cust.ID)
	plan.Del("test")
	coupon.Del("sub_coupon")
}
예제 #18
0
func TestInvoiceCreatedHandlerCustomPlan(t *testing.T) {
	testData := `
{
    "closed": false,
    "paid": false,
    "customer": "%s"
}`

	tests.WithConfiguration(t, func(c *config.Config) {
		stripe.Key = c.Stripe.SecretToken
		Convey("Given stub data", t, func() {
			withStubData(func(username, groupName, sessionID string) {
				group, err := modelhelper.GetGroup(groupName)
				tests.ResultedWithNoErrorCheck(group, err)

				// create custom test plan
				id := "p_c_" + bson.NewObjectId().Hex()
				pp := &stripe.PlanParams{
					Amount:        Plans[UpTo10Users].Amount,
					Interval:      plan.Month,
					IntervalCount: 1,
					TrialPeriod:   1,
					Name:          id,
					Currency:      currency.USD,
					ID:            id,
				}

				p, err := plan.New(pp)
				So(err, ShouldBeNil)

				const totalMembers = 9

				// subscribe to test plan
				params := &stripe.SubParams{
					Customer: group.Payment.Customer.ID,
					Plan:     p.ID,
					Quantity: totalMembers,
				}

				Convey("Even if we process customer with a custom plan we should require CC", func() {
					_, err := EnsureSubscriptionForGroup(group.Slug, params)
					So(err, ShouldEqual, ErrCustomerSourceNotExists)

					Convey("When custom plan holder has CC", func() {
						withTestCreditCardToken(func(token string) {
							// attach payment source
							cp := &stripe.CustomerParams{
								Source: &stripe.SourceParams{
									Token: token,
								},
							}
							c, err := UpdateCustomerForGroup(username, groupName, cp)
							tests.ResultedWithNoErrorCheck(c, err)

							Convey("We should be able to create subscription", func() {
								sub, err := EnsureSubscriptionForGroup(group.Slug, params)
								tests.ResultedWithNoErrorCheck(sub, err)

								// check if group has correct sub id
								groupAfterSub, err := modelhelper.GetGroup(groupName)
								tests.ResultedWithNoErrorCheck(groupAfterSub, err)
								So(sub.ID, ShouldEqual, groupAfterSub.Payment.Subscription.ID)

								Convey("When invoice.created is triggered with custom plan", func() {
									raw := []byte(fmt.Sprintf(
										testData,
										group.Payment.Customer.ID,
									))

									err := invoiceCreatedHandler(raw)
									So(err, ShouldBeNil)

									Convey("subscription id should stay same", func() {
										groupAfterHook, err := modelhelper.GetGroup(groupName)
										tests.ResultedWithNoErrorCheck(groupAfterHook, err)

										// group should have correct sub id
										So(sub.ID, ShouldEqual, groupAfterHook.Payment.Subscription.ID)

										count, err := (&models.PresenceDaily{}).CountDistinctByGroupName(group.Slug)
										So(err, ShouldBeNil)
										So(count, ShouldEqual, 0)

										Convey("we should clean up successfully", func() {
											sub, err := DeleteSubscriptionForGroup(group.Slug)
											tests.ResultedWithNoErrorCheck(sub, err)

											_, err = plan.Del(pp.ID)
											So(err, ShouldBeNil)
										})
									})
								})
							})
						})
					})
				})
			})
		})
	})
}
예제 #19
0
func TestInvoiceCreatedHandlerWithCouponAndAccountBalance(t *testing.T) {
	testData := `
{
    "id": "in_00000000000000",
    "object": "invoice",
    "amount_due": 0,
    "charge": null,
    "closed": false,
    "currency": "usd",
    "customer": "%s",
    "discount":{
      "object": "discount",
      "coupon": {
        "id": "QtadvP4t",
        "object": "coupon",
        "amount_off": %d,
        "created": 1473113335,
        "currency": "usd",
        "duration": "once",
        "valid": true
      },
      "customer": "cus_98mqDLgCNhwhIo",
      "end": null,
      "start": 1473113336,
      "subscription": null
    },
    "date": 1471348722,
    "ending_balance": 0,
    "forgiven": false,
    "livemode": false,
    "metadata": {},
    "next_payment_attempt": null,
    "paid": false,
    "period_end": 1471348722,
    "period_start": 1471348722,
    "receipt_number": null,
    "starting_balance": %d,
    "statement_descriptor": null,
    "subscription": "%s",
    "subtotal": %d,
    "tax": null,
    "tax_percent": null,
    "total": %d,
    "webhooks_delivered_at": 1471348722
}`
	tests.WithConfiguration(t, func(c *config.Config) {
		stripe.Key = c.Stripe.SecretToken
		Convey("Given stub data", t, func() {
			withStubData(func(username, groupName, sessionID string) {
				group, err := modelhelper.GetGroup(groupName)
				tests.ResultedWithNoErrorCheck(group, err)

				// add credit card to the user
				withTestCreditCardToken(func(token string) {
					var offAmount uint64 = 100
					var offBalance int64 = 200
					withTestCoupon(offAmount, func(couponCode string) {

						// attach payment source
						cp := &stripe.CustomerParams{
							// add our coupon
							Coupon: couponCode,
							// add some credit to user
							Balance: -offBalance,
							// add the CC
							Source: &stripe.SourceParams{
								Token: token,
							},
						}

						c, err := UpdateCustomerForGroup(username, groupName, cp)
						tests.ResultedWithNoErrorCheck(c, err)
						const totalMembers = 9
						// generate 9 members with a total of 1 deleted user (also there is an admin)
						generateAndAddMembersToGroup(group.Slug, totalMembers)

						// create test plan
						id := "p_" + bson.NewObjectId().Hex()
						pp := &stripe.PlanParams{
							Amount:        Plans[UpTo10Users].Amount,
							Interval:      plan.Month,
							IntervalCount: 1,
							TrialPeriod:   0,
							Name:          id,
							Currency:      currency.USD,
							ID:            id,
						}

						p, err := plan.New(pp)
						So(err, ShouldBeNil)

						// subscribe to test plan
						params := &stripe.SubParams{
							Customer: group.Payment.Customer.ID,
							Plan:     p.ID,
							Quantity: totalMembers,
						}

						sub, err := EnsureSubscriptionForGroup(group.Slug, params)
						tests.ResultedWithNoErrorCheck(sub, err)

						// check if group has correct sub id
						groupAfterSub, err := modelhelper.GetGroup(groupName)
						tests.ResultedWithNoErrorCheck(groupAfterSub, err)
						So(sub.ID, ShouldEqual, groupAfterSub.Payment.Subscription.ID)

						Convey("When invoice.created is triggered with right amount of total fee", func() {
							totalDiscount := uint64(offBalance) + offAmount
							raw := []byte(fmt.Sprintf(
								testData,
								group.Payment.Customer.ID,
								offAmount,
								-offBalance,
								sub.ID,
								Plans[UpTo10Users].Amount*totalMembers,
								(Plans[UpTo10Users].Amount*totalMembers)-(totalDiscount),
							))
							var capturedMails []*emailsender.Mail
							realMailSender := mailSender
							mailSender = func(m *emailsender.Mail) error {
								capturedMails = append(capturedMails, m)
								return nil
							}
							So(invoiceCreatedHandler(raw), ShouldBeNil)
							mailSender = realMailSender

							// this means we didnt change the subscription.
							So(len(capturedMails), ShouldEqual, 0)

							Convey("subscription id should stay same", func() {
								groupAfterHook, err := modelhelper.GetGroup(groupName)
								tests.ResultedWithNoErrorCheck(groupAfterHook, err)

								// group should have correct sub id
								So(sub.ID, ShouldEqual, groupAfterHook.Payment.Subscription.ID)

								count, err := (&models.PresenceDaily{}).CountDistinctByGroupName(group.Slug)
								So(err, ShouldBeNil)
								So(count, ShouldEqual, 0)

								Convey("we should clean up successfully", func() {
									sub, err := DeleteSubscriptionForGroup(group.Slug)
									tests.ResultedWithNoErrorCheck(sub, err)

									_, err = plan.Del(pp.ID)
									So(err, ShouldBeNil)
								})
							})
						})
					})
				})
			})
		})
	})
}
예제 #20
0
func TestInvoiceCreatedHandlerUpgradePlan(t *testing.T) {
	testData := `
{
    "id": "in_00000000000000",
    "object": "invoice",
    "amount_due": 0,
    "application_fee": null,
    "attempt_count": 0,
    "attempted": false,
    "charge": null,
    "closed": false,
    "currency": "usd",
    "customer": "%s",
    "date": 1471348722,
    "description": null,
    "discount": null,
    "ending_balance": 0,
    "forgiven": false,
    "livemode": false,
    "metadata": {},
    "next_payment_attempt": null,
    "paid": false,
    "period_end": 1471348722,
    "period_start": 1471348722,
    "receipt_number": null,
    "starting_balance": 0,
    "statement_descriptor": null,
    "subscription": "%s",
    "subtotal": %d,
    "tax": null,
    "tax_percent": null,
    "total": %d,
    "webhooks_delivered_at": 1471348722
}`

	tests.WithConfiguration(t, func(c *config.Config) {
		stripe.Key = c.Stripe.SecretToken
		Convey("Given stub data", t, func() {
			withStubData(func(username, groupName, sessionID string) {
				group, err := modelhelper.GetGroup(groupName)
				tests.ResultedWithNoErrorCheck(group, err)

				withTestCreditCardToken(func(token string) {
					// attach payment source
					cp := &stripe.CustomerParams{
						Source: &stripe.SourceParams{
							Token: token,
						},
					}

					c, err := UpdateCustomerForGroup(username, groupName, cp)
					tests.ResultedWithNoErrorCheck(c, err)

					const totalMembers = 9
					generateAndAddMembersToGroup(group.Slug, totalMembers)

					// create test plan
					id := "p_" + bson.NewObjectId().Hex()
					pp := &stripe.PlanParams{
						Amount:        Plans[UpTo10Users].Amount,
						Interval:      plan.Month,
						IntervalCount: 1,
						TrialPeriod:   0,
						Name:          id,
						Currency:      currency.USD,
						ID:            id,
					}

					p, err := plan.New(pp)
					So(err, ShouldBeNil)

					// subscribe to test plan
					params := &stripe.SubParams{
						Customer: group.Payment.Customer.ID,
						Plan:     p.ID,
						Quantity: totalMembers,
					}

					sub, err := EnsureSubscriptionForGroup(group.Slug, params)
					tests.ResultedWithNoErrorCheck(sub, err)

					// check if group has correct sub id
					groupAfterSub, err := modelhelper.GetGroup(groupName)
					tests.ResultedWithNoErrorCheck(groupAfterSub, err)
					So(sub.ID, ShouldEqual, groupAfterSub.Payment.Subscription.ID)

					// add 1 more user to force plan upgrade
					generateAndAddMembersToGroup(group.Slug, 1)

					Convey("When invoice.created is triggered with previous plan's amount", func() {
						raw := []byte(fmt.Sprintf(
							testData,
							group.Payment.Customer.ID,
							sub.ID,
							Plans[UpTo10Users].Amount*totalMembers,
							Plans[UpTo10Users].Amount*totalMembers,
						))

						var capturedMails []*emailsender.Mail
						realMailSender := mailSender
						mailSender = func(m *emailsender.Mail) error {
							capturedMails = append(capturedMails, m)
							return nil
						}
						So(invoiceCreatedHandler(raw), ShouldBeNil)
						mailSender = realMailSender

						// check we are sending events on subscription change.
						So(len(capturedMails), ShouldEqual, 1)
						So(capturedMails[0].Subject, ShouldEqual, eventNameJoinedNewPricingTier)
						So(len(capturedMails[0].Properties.Options), ShouldBeGreaterThan, 1)
						oldPlanID := capturedMails[0].Properties.Options["oldPlanID"]
						newPlanID := capturedMails[0].Properties.Options["newPlanID"]
						So(oldPlanID, ShouldNotBeBlank)
						So(newPlanID, ShouldNotBeBlank)
						So(newPlanID, ShouldNotEqual, oldPlanID)

						Convey("subscription id should not stay same", func() {
							groupAfterHook, err := modelhelper.GetGroup(groupName)
							tests.ResultedWithNoErrorCheck(groupAfterHook, err)

							// group should have correct sub id
							So(sub.ID, ShouldNotEqual, groupAfterHook.Payment.Subscription.ID)

							sub, err := GetSubscriptionForGroup(groupName)
							tests.ResultedWithNoErrorCheck(sub, err)

							So(sub.Plan.ID, ShouldEqual, UpTo50Users)

							count, err := (&models.PresenceDaily{}).CountDistinctByGroupName(group.Slug)
							So(err, ShouldBeNil)
							So(count, ShouldEqual, 0)

							Convey("we should clean up successfully", func() {
								sub, err := DeleteSubscriptionForGroup(group.Slug)
								tests.ResultedWithNoErrorCheck(sub, err)

								_, err = plan.Del(pp.ID)
								So(err, ShouldBeNil)
							})
						})
					})
				})
			})
		})
	})
}