Giter Site home page Giter Site logo

recurly-client-dotnet's Issues

Subscription Preview method is broken

The Recurly API endpoint PreviewSubscription now returns a child node for invoice which the ReadXml method in Subscription.cs is not set up to handle.

https://github.com/recurly/recurly-client-net/blob/cfff76bbaf35ccfbf7cfe741c0136063e868ec38/Library/Subscription.cs#L427

What's happening is this switch case is correctly reading the State element from the subscription XML, but then the reader starts to traverse the invoice and sees a State element there as well. The issue is that the code is trying to parse the enum for the invoice state which isn't in the SubscriptionType enum.

I believe all that needs to be done is to check for the existence of the invoice and call out to Invoice.cs to read the xml.

Transaction object missing description property

Current commit of transaction object is missing "description". When creating new transactions via the API this results in customer invoices with a blank description field.

No deleterious effects in the code however results in confusion when reconciling charges via invoices.

Product code not available in C# API?

product_code is available for adjustments through the api xml- yet there is no property in the adjustments.cs class to get/set the value? I'm wondering why this is?

I have a plan add on with an "add-on code" of "XYZ" in the recurly UI. When a payment is processed - I am getting a web hook telling me of the successful payment. I then use the API to get the adjustments on that invoice. When I pull the adjustments, I'm trying to find out what the adjustment is for by either the accounting_code or the product_code (unique). In this case - I get a adjustment with origin of add_on, but the accounting_code is blank and the product_code is not available in the C#. When I pull report though recurly UI - I see add-on code is set as product_code, so I assume that's the code I need to use? I included it in my local project (get only), but was wondering why this is left off the project? How am I supposed to uniquely identify my add_on for processing via the api/C#?

Thanks!

Unable to add description when submitting a one-off transation

While the general API documentation mentions you can pass in a 'description' when submitting a new one-off transaction, the .Net Recurly-Api-Client v. 1.1.6.0 doesn't allow you to do so. Neither of the two provided constructors support including a description. Further, it doesn't appear that there is a public description field on the class so I am unable to add it after initialization either.

The documentation I’m referring to can be found here: https://docs.recurly.com/api/transactions under “Create transaction.”

Code snippet for signature generation

Hi!

Could anybody provide a code snippet in C# for Recurly signature generation/verification?

I can't find this code in sources...

Any help will be greatly appreciated. Many thanks in advance!

Update billing info with token not working

code

       var account = Accounts.Get(AccountId);
       var info = account.BillingInfo;
        if (!String.IsNullOrEmpty(model.RecurlyToken))
        {
            info.TokenId = model.RecurlyToken;
            info.Update();
        }

But in the Xml sent, it is sending all of the billing info not just the token

<billing_info>
<first_name>Simon</first_name>
<last_name>Simple</last_name>
Test
Crows Nest
NSW
1585
AU
<ip_address>203.206.181.135</ip_address>
<token_id>YxhDoZU2mv89UalVwmEJRg</token_id>
</billing_info>

Error response (not handled BTW throws exception)

billing_info_invalid no other attributes are allowed when a token is provided

No way to change a plan code

It seems that it is not possible to update a plan code. When Plan.Update() is called, the client create PUT request to /plans/:plan_code where ":plan_code" is the new (changed) value. Since there is no plan with that code at the time when Update() is called, NotFoundException is thrown.

Maybe, method override like Update(string planCode) could be a solution here.

Transactions Get By Start DateTime

I would like to the ability to query transactions and accounts at a specific date and time down to the millisecond or whatever the most accurate unit is available in your data structure. A common query would be able to supply a specific start date time as in input parameter. Another parameter would be the direction of data: ascending or descending (forward or backward). Another parameter might be read-only, since this may speed up the call and take less overhead depending upon the underlying data structure.

Example: If you wanted to return 200 transactions to start at August 1, 2014 at two fifteen pm
it would be expressed as: 08-01-2014 14:15:00
DataDirection = 1;
PageSize =200;
Transactions.GetByStartTime (DateTime, Data Direction, PageSize)

This would return 200 records starting at the time indicated. Depending upon the type of business 200 records may be weeks or might be a couple of seconds. Based on what is returned I can make another call using the start time being the same or a slight increment of the last record supplied by the previous call.

Record set returned : (using a base of zero)
Record 0 2014-08-01 14:15:00 143
Record 1 2014-08-01 14:15:00 350
Record 2 2014-08-01 14:15:01 080

Record 199 2014-08-01 14:15:05 000 (last record returned)

I would take the last record returned from the first call and add milliseconds to it.

08-01-2014 14:15:05 001
DataDirection = 1;
PageSize =200;
Transactions.GetByStartTime (DateTime, Data Direction, PageSize)

This would get around the pagination issue

ChangeSubscription with Addon removal doesn't update subscription addon quantity

I noticed that whenever i want to change a subscription that had a single addon item, to one that has no addons, the subscription addon isn't updated in recurly (still get return code of 2xx).

I remove the item like so (simplified)

var subscription = recurly.GetSubscription(account);
subscription.AddOns.RemoveAt(0);
recurly.ChangeSubscription(subscription, Subscription.ChangeTimeframe.Renewal);

As a workaround, I created the xml for the request myself, and noticed that if the element "subscription_add_ons" is not present, then recurly ignores the change to the addon. When I add this element, and instead leave the "subscription_add_on" element block(s) blank, the subscription is updated, and I see the pending subscription as i would expect.

I believe the issue lies in Subscription.cs line 581 in the WriteChangeSubscriptionXml method. (Added comment to point out line)

xmlWriter.WriteStartElement("subscription"); // Start: subscription
xmlWriter.WriteElementString("timeframe", timeframe.ToString().EnumNameToTransportCase());
xmlWriter.WriteElementString("quantity", Quantity.AsString());
xmlWriter.WriteStringIfValid("plan_code", _planCode);

xmlWriter.WriteIfCollectionHasAny("subscription_add_ons", AddOns); //<------This line here

xmlWriter.WriteStringIfValid("coupon_code", _couponCode);

When I dive down deeper into XmlWriterExtensions.cs, i noticed that the collection name is not written in the method call. (Added comment to point out lines)

if (!items.HasAny()) return;  //<---- return before necessary collection name block is written for addon remvoal
writer.WriteStartElement(collectionName); //<--- in this case, if we write this with its end, we get the desired results
foreach (var item in items)
{
    writer.WriteElementString(localName(item), stringValue(item));
}
writer.WriteEndElement();

I haven't done the research to know if any other element blocks behave this way, so this may be a bug with the recurly api, not the .net client, but for this case at least, the collection name block must exist for the change to work.

Upcoming multiple coupons

It appears that multiple coupons per account are in beta according to this page: https://docs.recurly.com/coupons-beta

Is there currently anyone assigned to implementing these changes once the API is finalized? If not, I'm thinking a new branch could be made immediately and work started via pull request. A separate beta account could also be setup and linked to the branch to test with. Once the coupon changes are out of beta we can make any file changes if necessary and merge into master branch. By starting now we could have an update out soon after the coupon changes go into production.

I'm open to taking this on if you guys don't have someone working on it already.

Invoices are broken - API calls using this project are crashing getting invoices

The XML doc being parsed has two elements of "state".

one state is under address and the other one is for the invoice.

The StringExtensions.cs code is crashing on:
public static T ParseAsEnum(this string source)
{
var sanitized = source.ToPascalCase();
if (sanitized.IsNullOrEmpty())
throw new ArgumentException("Cannot convert a null or empty string to an Enumeration.", "source");

        return (T)Enum.Parse(typeof(T), sanitized, true);
    }

because it's being passed the address state before the invoice state.

This is from Invoice.cs

internal override void ReadXml(XmlTextReader reader)
{
while (reader.Read())
{
// End of invoice element, get out of here
if (reader.Name == "invoice" && reader.NodeType == XmlNodeType.EndElement)
break;

            if (reader.NodeType != XmlNodeType.Element) continue;

            switch (reader.Name)
            {
                case "account":
                    var accountHref = reader.GetAttribute("href");
                    AccountCode = Uri.UnescapeDataString(accountHref.Substring(accountHref.LastIndexOf("/") + 1));
                    break;

                case "subscription":
                    var subHref = reader.GetAttribute("href");
                    SubscriptionUuid = Uri.UnescapeDataString(subHref.Substring(subHref.LastIndexOf("/") + 1));
                    break;

                case "uuid":
                    Uuid = reader.ReadElementContentAsString();
                    break;

                case "state":
                    State = reader.ReadElementContentAsString().ParseAsEnum<InvoiceState>();
                    break;

                case "invoice_number":
                    int invNumber;
                    if (Int32.TryParse(reader.ReadElementContentAsString(), out invNumber))
                        InvoiceNumber = invNumber;
                    break;

                case "po_number":
                    PoNumber = reader.ReadElementContentAsString();
                    break;

                case "vat_number":
                    VatNumber = reader.ReadElementContentAsString();
                    break;

                case "subtotal_in_cents":
                    SubtotalInCents = reader.ReadElementContentAsInt();
                    break;

                case "tax_in_cents":
                    TaxInCents = reader.ReadElementContentAsInt();
                    break;

                case "total_in_cents":
                    TotalInCents = reader.ReadElementContentAsInt();
                    break;

                case "currency":
                    Currency = reader.ReadElementContentAsString();
                    break;

                case "created_at":
                    DateTime createdAt;
                    if (DateTime.TryParse(reader.ReadElementContentAsString(), out createdAt))
                        CreatedAt = createdAt;
                    break;

                case "closed_at":
                    DateTime closedAt;
                    if (DateTime.TryParse(reader.ReadElementContentAsString(), out closedAt))
                        ClosedAt = closedAt;
                    break;

                case "tax_type":
                    TaxType = reader.ReadElementContentAsString();
                    break;

                case "tax_rate":
                    TaxRate = reader.ReadElementContentAsDecimal();
                    break;

                case "net_terms":
                    NetTerms = reader.ReadElementContentAsInt();
                    break;

                case "collection_method":
                    CollectionMethod = reader.ReadElementContentAsString();
                    break;

                case "line_items":
                    // overrite existing value with the Recurly API response
                    Adjustments = new AdjustmentList();
                    Adjustments.ReadXml(reader);
                    break;

                case "transactions":
                    // overrite existing value with the Recurly API response
                    Transactions = new TransactionList();
                    Transactions.ReadXml(reader);
                    break;
            }
        }
    }

As of right now - getting any invoices does not seem to work.

ChangeSubscription requires cost of new plan

I am not sure if this is be design or not, but when changing the subscription, the price does not update. For example: If a user is on Plan-A that costs $15 and I use the API to change them to Plan-B which is $5, the plan updates but the price does not. I have to include the price of the new subscription in order to get it to update.

            var subscription = GetRecurlySubscription(Member.MemberID.ToString());
            Plan newPlan = Plans.Get(Member.PlanCode);
            if (subscription != null && newPlan != null)
            {   
                subscription.Plan = newPlan;
                subscription.UnitAmountInCents = newPlan.UnitAmountInCents.Values.FirstOrDefault();
                subscription.ChangeSubscription(Subscription.ChangeTimeframe.Now);                    
            }

Changing Private Api Key at Runtime

The private apiKey for recurly is defined in a configuration section. If you use two different recurly accounts (one for production, and one for testing -- which is how recurly recommends you set up testing), you are not able to make a decision at run time about which key / account to use.

Need to add a feature to allow the private api key to be modified at run time.

account.Create() when no BillingInfo.

Getting a "Object reference not set to an instance of an object." error when trying to create an account. Turns out BillingInfo cannot be null. Billing info requires account to instantiate.

What should happen first?

Type RecurlySection doesn't exist

My project was failing because the Config file specified the config type as:

per documentation. In the Recurly project the Type is Recurly.Configuration.Section.

A class representing Notifications?

Today we have to covert Notifications xml into objects in our own custom way. Would be nice to have a "RecurlyNotification" class. At a minimum, if the "ReadXml" methods were public, it'd make our lives easier.

ReActivate Subscription

if you use Recurly.RecurlySubscription.CancelSubscription(AccountCode) there is no implementation to reverse it like Recurly.RecurlySubscription.ReActivateSubscription(AccountCode)

it is available on API but not in this wrapper. the code below should be in RecurlySubscription.cs

        /// 
        /// ReActivate a passive subscription.
        /// 
        /// Subscriber's Account Code
        public static void ReActivateSubscription(string accountCode)
        {
            string reactivateUrl = String.Format("{0}/reactivate", SubscriptionUrl(accountCode));
            RecurlyClient.PerformRequest(RecurlyClient.HttpRequestMethod.Post, reactivateUrl);
        }

Recurly API docs don't match the code - can't clear AddOns

As per https://docs.recurly.com/api/subscriptions/subscription-add-ons

The following should work:
// remove an add-on
subscription.AddOns.RemoveAt(0);

// remove all add-ons
subscription.AddOns.Clear();

But in the code - the recurlylist shows these methods as "internal" - can't access them. (public class SubscriptionAddOnList : RecurlyList)

internal void Clear()
{
Items.Clear();
}

internal void RemoveAt(int i)
{
Items.RemoveAt(i);
}

Need to make public so we can use?

Connection times out to Recurly api server on Recurly.Plans.List()

Every 2-3 hours I get the following in my logs, looks like Recurly api server is failing?

It's always on the Recurly.Plans.List() function. Perhaps that just because we call this API the most. Seen these for months now, and it re-occurs every few weeks or so. Is it the library or the server/api?

System.Net.Sockets.SocketException: A connection attempt failed because the

connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 64.74.141.63:443 at

System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress) at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6,

Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Exception& exception) --- End of inner exception stack trace --- at

System.Net.HttpWebRequest.GetResponse() at Recurly.Client.PerformRequest(HttpRequestMethod method, String urlPath, WriteXmlDelegate writeXmlDelegate, ReadXmlDelegate readXmlDelegate,

ReadXmlListDelegate readXmlListDelegate) at Recurly.Client.PerformRequest(HttpRequestMethod method, String urlPath, ReadXmlListDelegate readXmlListDelegate) at

Recurly.RecurlyList`1.GetItems() at Recurly.Plans.List()

merchant reported removal of all subscription add ons defunct

"The RemoveAt() call is a method on the .NET List object and thus runs no functional code against Recurly. It simply removes the item from the list.

The issue is not removing a single SubscriptionAddOn but rather manifests when all addOns for a subscription are removed. As long as there is at least 1, the code functions as expected. When all addOns are removed, the subscription_add_ons XML element is not written to the request by the C# client and it appears that the Recurly API takes no action when this collection parent element is not found. "

Getting AddOns from Plan -> Addons doesn't populate PlanCode for add on

Consider the following pseudo code.

var plan = Plans.Get("some plan code")
plan.AddOns[0].GetHashCode() //Exception

The problem is that when the AddOns collection is fetched the PlanCode property is not set in the ReadXml method of the AddOn class. The AddOn class overrides GetHashCode which just does return PlanCode.GetHashCode(); Since the property is null GetHashCode naturally fails.

https://github.com/recurly/recurly-client-net/blob/master/Library/AddOn.cs#L102

I discovered this as I'm using Automapper and it uses GetHashCode internally.

Add Webhooks support

Would love to see some basic Webhooks support in the .NET client. Currently I have to manually deserialize the webhook requests.

invoice pdf download

Hi,

I want to display a particular invoice in pdf format using the .NET API. If anybody has done it earlier, please help me with it.

Regards
Atul

Lists handling impovements suggestion

Hi,

I wanted to mention a couple of suggestions regarding how Recurly lists are accessed through the wrapper.

It would be really nice if the following capabilities were available:

  1. Abilility to override default page size (that is specified in configuration settings) on a method-by-method basis
  2. Abililty to optionally specify StartUrl in methods that return paged lists (in order to be able to leverage the internal paging support for higher level APIs built using this wrapper library).

Thanks!

Subscription.Postpone should not trim time from Date

See Postpone method... The ToString() is removing time from the renewal. The UI does support date and time. Change formatter to "yyyy-MM-ddThh:mm:ssZ"

public void Postpone(DateTime nextRenewalDate)
{
Client.Instance.PerformRequest(Client.HttpRequestMethod.Put,
UrlPrefix + Uri.EscapeUriString(Uuid) + "/postpone?next_renewal_date=" + nextRenewalDate.ToString("yyyy-MM-dd"),
ReadXml);
}

Get Tests and CI running

In the rest of our libraries, we use travis to run the tests and don't merge anything where the tests do not pass. We should be doing the same thing in this library. In order to do this, we should add a travis config and fix the tests (or remove the ones that aren't working). Once we have travis protecting PRs we can get more serious about adding tests for each change.

@MuffinMan10110 let me know if you have any input on this. I plan to get this done in the next few weeks.

Issue on C# UTC dates when trying to "Unpostpone" a subscription

We're trying to unpostone a subscription by activating it once again. we are doing it like this:

var subscription = Subscriptions.Get("31d13867f5510236cb26244c13823a45");
subscription.Postpone(DateTime.UtcNow.AddMinutes(1));

The problem here is that according to your support there is a time discrepancy between what is entered in the api, and what is seen arriving in the server logs (approx. -12 hour difference). If I use AddDays(1) instead of plus 1 minute it works. However we do need it to be 1 minute right after.

It appears to be dependent upon the scripting language used as PHP apparently does not have this issue, although C# has.

Example of date being sent on our side and that seems to be correct:

DateTime.UtcNow.AddMinutes(1)
    {10/13/2015 6:33:37 PM}
    Date: {10/13/2015 12:00:00 AM}
    Day: 13
    DayOfWeek: Tuesday
    DayOfYear: 286
    Hour: 18
    Kind: Utc
    Millisecond: 93
    Minute: 33
    Month: 10
    Second: 37
    Ticks: 635803580170937320
    TimeOfDay: {18:33:37.0937320}
    Year: 2015

Addon UnitPriceInCents overriden by subscription plan UnitPriceInCents

If you get a subscription plan and then get an AddOn related to that subscription, create a new subscription using that plan and then attempt to add any AddOns to that subscription - all subscription AddOns for that subscription have their UnitPriceInCents set to the same UnitPriceInCents that the plan has instead of what it should have for the AddOn.

See code and comments below.

          //UnitPriceInCents for this plan is 2500
          Plan plan = Plans.Get("MyPlan"); 

          //Make a new subscription using this plan
          Subscription subscription = new Subscription(account, plan, "GBP");

          //Get an AddOn related to Plan, on inspection UnitPriceInCents is 1000
          AddOn myAddOn = plan.GetAddOn("MyAddOn");

          //Add AddOn to new subscription
          subscription.AddOns.Add(myAddOn, 1);

          //As soon as this is done, if you inspect the subscription and then look
          //at the UnitPriceInCents of the AddOn you added, the UnitPriceInCents is now 
          //2500 (The UnitPriceInCents of the plan) instead of the UnitPriceInCents of the 
          //AddOn which was 1000 until we added it to the suscription.                

          subscription.Create();

I cannot change the UnitPriceInCents either, as this is read only within the .NET library, which makes no sense as you can define these in XML using the HTTPRequest method.

Client doesn't properly handle Bad Request responses

For example, attempting to terminate a subscription that is expired will result in the following response:

HTTP/1.1 400 Bad Request
<?xml version="1.0" encoding="UTF-8"?>
<error>
  <symbol>invalid_transition</symbol>
  <description>A expired subscription can't transition to expired</description>
</error>

Client.cs doesn't appear to have a switch condition for this HTTP status so what ends up getting propagated back to the client is The remote server returned an error: (400) Bad Request. It really should be returning a RecurlyException with the error above inside the Errors array. Additionally since there's only one error we can set the Message property to the description in the error.

https://github.com/recurly/recurly-client-net/blob/master/Library/Client.cs#L169

Add-on Clear and Add-on Remove is not working

Add-on clear and add-on remove is not working. The code below used from the documentation
https://docs.recurly.com/api/subscriptions/subscription-add-ons
is not changing the add-ons of the subscriptions....

var subscription = Subscriptions.Get("2bc2a33060c103d2f0c0b5430b94d2b2");

// remove an add-on
subscription.AddOns.RemoveAt(0);

// remove all add-ons
subscription.AddOns.Clear();

// call for an update
subscription.ChangeSubscription(Subscription.ChangeTimeframe.Now);

Can we refactor Subscription.UpdateNotes method?

The update notes method https://github.com/recurly/recurly-client-net/blob/master/Library/Subscription.cs#L398 currently takes a dictionary as an argument.

There's a couple reasons this is a bad idea:

  1. No one knows what keys are excepted
  2. The way UpdateNotes handles the dictionary you must provide all 3 notes even if you want to just update one.

I suggest we change the signature to:
public void UpdateNotes(string termsConditions, string customerNotes, string vatChargeNotes) this way you can simply pass null to any ones you don't want to update.

Enumerations inside instance type

When I was retrieving plans I needed to combine information into another type for display. withing the Plan type the [x]IntervalUnit properties are of the enum type IntervalUnit. The IntervalUnit Enumeration is contained within the In Plans class making it for all practical purposes unusable in any assembly that references the Recurly.net client assembly.

Best practice for enumerations is to declare them outside of the class in the namespace to allow developers to reference them in referring assemblies.

I would recommend that IntervalUnit and any other enumerations be moved to the namespace.

'System.Net.WebException' occurred in Recurly.dll

I have included Recurly.dll in my project. I have a test account with account code "test" and I am trying to update billing information. Billing info gets updated successfully if I do the following;

        var account = Accounts.Get("test");
        var info = account.BillingInfo;
         info.FirstName = "Verana";
         info.LastName = "Example";
         info.PhoneNumber = "111-111-1111";
         info.VerificationValue = "123";    
         info.ExpirationMonth = 11;
         info.ExpirationYear = 2015;
         info.Update();

but if I use Token Id generated by recurly.js i.e.,

         info.TokenId = tokenIdFromjs;
         info.Update();

The following error occurs in Client.cs

An exception of type 'System.Net.WebException' occurred in Recurly.dll but was not handled in user code
Additional information: The remote server returned an error: (400) Bad Request.

In am generating the token using the following test data object

            var billingInfo = {
                      number: '4111-1111-1111-1111',
                      month: '1',
                      year: '18',
                      first_name: 'John',
                      last_name: 'Rambo',
                      cvv: '123',
                      address1: '123 Main St.',
                      address2: 'Unit 1',
                      city: 'Hope',
                     state: 'WA',
                     postal_code: '98552',
                     country: 'US',
                     vat_number: 'SE0000'
             };
              recurly.token(billingInfo, tokenHandler);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.