Happy Business Starts Here

Re: Zuora client generated code "csharp-dotnet2-client" does not return actual model.

Honor Student

Zuora client generated code "csharp-dotnet2-client" does not return actual model.

download the latest version of Zuora's Swagger spec from https://assets.zuora.com/zuora-documentation/swagger.yaml .

 

And then paste yaml to https://editor.swagger.io/ to generate "csharp-dotnet2-client" for my asp.net core api app to be used.

 

In 'CatalogApi.cs', 

public GETCatalogType GETCatalog(string zuoraEntityIdsintpageSizestring zuoraVersion){

}

The return type 

GETCatalogType

is not the same as the response json when I call it from postman. 

The response json from postman is the same as sample json at https://www.zuora.com/developer/api-reference/#operation/GET_Catalog
which contain id, sku, name, productRatePlans and so on. 

 

But 'GETCatalogType' does not contains these properties. 

Do I miss something at generating client c# code?  Thanks

 

8 REPLIES 8
Zuora Documentation

Re: Zuora client generated code "csharp-dotnet2-client" does not return actual model.

Hi @sqian,

 

I don't think you missed anything. It looks like you're running into an issue that we also discovered recently. 

 

The GETCatalogType class is OK I think. But GETCatalogType has a property called 

Products, which is an array of GETProductType instances, and GETProductType is missing all the properties id, sku, name and so on.
 
I've attached a modified Swagger spec to this reply. Please could you try regenerating the csharp-dotnet2-client using this Swagger spec and let me know the outcome? Thank you!
Honor Student

Re: Zuora client generated code "csharp-dotnet2-client" does not return actual model.

Hi David,

 

Appreciate your answer. I have verified your swagger spec file. It does contain these missing fields. 

 

I will check the other type such as Subscription, account and so on tomorrrow. If they all match with documentation of developer portal, I will let you know here.  Thank you so much. 

 

Stanley

QSR International

Honor Student

Re: Zuora client generated code "csharp-dotnet2-client" does not return actual model.

Hi David,

 

The new swagger json works for catelog type and so on. 

However I have issue for the subscription. 

 

Create Subscription https://www.zuora.com/developer/api-reference/#operation/POST_Subscription
"chargeOverrides":

"chargeOverrides": [
{
"billCycleDay": "5",
"billCycleType": "SpecificDayofMonth",
"billingPeriodAlignment": "AlignToCharge",
"billingTiming": "IN_ARREARS",
"description": "This is rate plan charge description",
"number": "TestCharge",
"price": 12.01,
"productRatePlanChargeId": "ff8080811ca15d19011cddad8c953b53",
"triggerDate": "2015-09-01",
"triggerEvent": "USD"
}
]

The 'chargeOverrides' json is not matching the generated type as follow. 

namespace IO.Swagger.Model
{

    /// <summary>
    /// Charge associated with a rate plan. 
    /// </summary>
    [DataContract]
    public class ChargeOverride
    {
        /// <summary>
        /// Gets or Sets Billing
        /// </summary>
        [DataMember(Name = "billing", EmitDefaultValue = false)]
        [JsonProperty(PropertyName = "billing")]
        public ChargeOverrideBilling Billing { get; set; }

        /// <summary>
        /// Charge number of the charge. For example, C-00000307.  If you do not set this field, Zuora will generate the charge number. 
        /// </summary>
        /// <value>Charge number of the charge. For example, C-00000307.  If you do not set this field, Zuora will generate the charge number. </value>
        [DataMember(Name = "chargeNumber", EmitDefaultValue = false)]
        [JsonProperty(PropertyName = "chargeNumber")]
        public string ChargeNumber { get; set; }

        /// <summary>
        /// Gets or Sets CustomFields
        /// </summary>
        [DataMember(Name = "customFields", EmitDefaultValue = false)]
        [JsonProperty(PropertyName = "customFields")]
        public RatePlanChargeObjectCustomFields CustomFields { get; set; }

        /// <summary>
        /// Description of the charge. 
        /// </summary>
        /// <value>Description of the charge. </value>
        [DataMember(Name = "description", EmitDefaultValue = false)]
        [JsonProperty(PropertyName = "description")]
        public string Description { get; set; }

        /// <summary>
        /// Gets or Sets EndDate
        /// </summary>
        [DataMember(Name = "endDate", EmitDefaultValue = false)]
        [JsonProperty(PropertyName = "endDate")]
        public EndConditions EndDate { get; set; }

        /// <summary>
        /// Gets or Sets Pricing
        /// </summary>
        [DataMember(Name = "pricing", EmitDefaultValue = false)]
        [JsonProperty(PropertyName = "pricing")]
        public ChargeOverridePricing Pricing { get; set; }

        /// <summary>
        /// Internal identifier of the product rate plan charge that the charge is based on. 
        /// </summary>
        /// <value>Internal identifier of the product rate plan charge that the charge is based on. </value>
        [DataMember(Name = "productRatePlanChargeId", EmitDefaultValue = false)]
        [JsonProperty(PropertyName = "productRatePlanChargeId")]
        public string ProductRatePlanChargeId { get; set; }

        /// <summary>
        /// Revenue Recognition Code 
        /// </summary>
        /// <value>Revenue Recognition Code </value>
        [DataMember(Name = "revRecCode", EmitDefaultValue = false)]
        [JsonProperty(PropertyName = "revRecCode")]
        public string RevRecCode { get; set; }

        /// <summary>
        /// Specifies the revenue recognition trigger condition.    * `Contract Effective Date`    * `Service Activation Date`   * `Customer Acceptance Date` 
        /// </summary>
        /// <value>Specifies the revenue recognition trigger condition.    * `Contract Effective Date`    * `Service Activation Date`   * `Customer Acceptance Date` </value>
        [DataMember(Name = "revRecTriggerCondition", EmitDefaultValue = false)]
        [JsonProperty(PropertyName = "revRecTriggerCondition")]
        public string RevRecTriggerCondition { get; set; }

        /// <summary>
        /// Specifies the revenue recognition rule.    * `Recognize upon invoicing`    * `Recognize daily over time` 
        /// </summary>
        /// <value>Specifies the revenue recognition rule.    * `Recognize upon invoicing`    * `Recognize daily over time` </value>
        [DataMember(Name = "revenueRecognitionRuleName", EmitDefaultValue = false)]
        [JsonProperty(PropertyName = "revenueRecognitionRuleName")]
        public string RevenueRecognitionRuleName { get; set; }

        /// <summary>
        /// Gets or Sets StartDate
        /// </summary>
        [DataMember(Name = "startDate", EmitDefaultValue = false)]
        [JsonProperty(PropertyName = "startDate")]
        public TriggerParams StartDate { get; set; }

        /// <summary>
        /// Unique identifier for the charge. This identifier enables you to refer to the charge before the charge has an internal identifier in Zuora.  For instance, suppose that you want to use a single order to add a product to a subscription and later update the same product. When you add the product, you can set a unique identifier for the charge. Then when you update the product, you can use the same unique identifier to specify which charge to modify. 
        /// </summary>
        /// <value>Unique identifier for the charge. This identifier enables you to refer to the charge before the charge has an internal identifier in Zuora.  For instance, suppose that you want to use a single order to add a product to a subscription and later update the same product. When you add the product, you can set a unique identifier for the charge. Then when you update the product, you can use the same unique identifier to specify which charge to modify. </value>
        [DataMember(Name = "uniqueToken", EmitDefaultValue = false)]
        [JsonProperty(PropertyName = "uniqueToken")]
        public string UniqueToken { get; set; }


        /// <summary>
        /// Get the string presentation of the object
        /// </summary>
        /// <returns>String presentation of the object</returns>
        public override string ToString()
        {
            var sb = new StringBuilder();
            sb.Append("class ChargeOverride {\n");
            sb.Append("  Billing: ").Append(Billing).Append("\n");
            sb.Append("  ChargeNumber: ").Append(ChargeNumber).Append("\n");
            sb.Append("  CustomFields: ").Append(CustomFields).Append("\n");
            sb.Append("  Description: ").Append(Description).Append("\n");
            sb.Append("  EndDate: ").Append(EndDate).Append("\n");
            sb.Append("  Pricing: ").Append(Pricing).Append("\n");
            sb.Append("  ProductRatePlanChargeId: ").Append(ProductRatePlanChargeId).Append("\n");
            sb.Append("  RevRecCode: ").Append(RevRecCode).Append("\n");
            sb.Append("  RevRecTriggerCondition: ").Append(RevRecTriggerCondition).Append("\n");
            sb.Append("  RevenueRecognitionRuleName: ").Append(RevenueRecognitionRuleName).Append("\n");
            sb.Append("  StartDate: ").Append(StartDate).Append("\n");
            sb.Append("  UniqueToken: ").Append(UniqueToken).Append("\n");
            sb.Append("}\n");
            return sb.ToString();
        }

        /// <summary>
        /// Get the JSON string presentation of the object
        /// </summary>
        /// <returns>JSON string presentation of the object</returns>
        public string ToJson()
        {
            return JsonConvert.SerializeObject(this, Formatting.Indented);
        }

    }
}

Can you please check if there are missing update for this swagger.json? Thanks. 

 

 

 

Zuora Documentation

Re: Zuora client generated code "csharp-dotnet2-client" does not return actual model.

Hi @sqian, glad to hear that GETCatalogType is working well.

 

To address your follow up question - I believe you are seeing a mismatch because the ChargeOverride class is not related to "Create subscription". It's related to a different part of the API (specifically, Orders).

 

Instead of the ChargeOverride class, I think you want to look at the POSTScCreateType class. Because in the request body of "Create subscription", the class corresponding to chargeOverrides is called POSTScCreateType.

 

Here's a bit more detail:

 

  • The class for the request body is POSTSubscriptionType. This class has an attribute called subscribeToRatePlans, which is a list of POSTSrpCreateType instances.

  • The POSTSrpCreateType class has an attribute called chargeOverrides, which is a list of POSTScCreateType instances.

 

Hope this helps!

Honor Student

Re: Zuora client generated code "csharp-dotnet2-client" does not return actual model.

Hi David, thanks for your correction. 

 

I have one sample json to test this. 

{
    "invoiceOwnerAccountKey": "A00017508",
    "accountKey": "A00017509",
    "EndUserAccount__c": "End User API",
    "PurchaseOrder__c": "",
    "Paid__c": "False",
    "collect": false,
    "BillingType__c": "ManualOrder",
    "Channel__c": "Indirect",
    "invoiceSeparately": true,
    "contractEffectiveDate": "2019-09-02",
    "termType": "TERMED",
    "initialTerm": 1,
    "initialTermPeriodType": "Week",
    "renewalTerm": "0",
    "autoRenew": false,
    "subscribeToRatePlans": [
        {
            "productRatePlanId": "8adc9dee6cdb852e016ce08155ab095d",
            "chargeOverrides": [
                {
                    "productRatePlanChargeId": "8adc9dee6cdb852e016ce08155d6095f",
                    "quantity": 1
                }
            ]
        },
        {
            "productRatePlanId": "8adcd9eb6d485afb016d4bfcbd502d13",
            "chargeOverrides": [
                {
                    "productRatePlanChargeId": "8adcd9eb6d485afb016d4bfcbd732d15",
                    "discountPercentage": 5
                }
            ]
        },
        {
            "productRatePlanId": "8adce4216b9de86d016bb0e29fae728c",
            "chargeOverrides": [
                {
                    "productRatePlanChargeId": "8adce4216b9de86d016bb0e29fcb728e",
                    "discountPercentage": 15
                }
            ]
        }
    ]
}

But it returned failure with: 

{
  "success" : false,
  "processId" : "557E3A714BFB8C50",
  "reasons" : [ {
    "code" : 53020230,
    "message" : "Field 'quantity' is not available for charges with the Discount-Percentage charge model."
  } ]
}

I know if quantity is not specified, it will be 0. But it seems 'quantity' and 'discountPercentage' exclude each other. How would I resolve this? 
And I also found the DiscountPercentage is string, but in other model it is decimal?. 

Thanks.
Stanley

 

Zuora Documentation

Re: Zuora client generated code "csharp-dotnet2-client" does not return actual model.

Hi Stanley,

 

Looking in the documentation for Create subscription, it seems that several fields are listed as strings instead of numeric types. This is what's causing 'DiscountPercentage' etc to be strings in the 'POSTScCreateType' class. We'll review the field types to see which ones need changing in the documentation. Thanks for raising this issue.

 

I've investigated the reason why 'quantity' is always included in the JSON that's sent to Zuora from the C# library. The C# library uses Newtonsoft.Json to serialize objects to JSON. By default, Newtonsoft.Json writes null values to JSON when serializing. That means that even if 'quantity' is null in a 'POSTScCreateType' object, the serialized JSON will still include 'quantity' - which I believe is causing the error you're receiving from Zuora.

 

The behavior of the JSON serializer can be controlled by the NullValueHandling setting. Specifically, it seems possible to use JsonConvert.DefaultSettings to override the default behavior and have the JSON serializer ignore null values.

 

After some playing around, I'd recommend that you add this early on in your code (before making any API calls):

 

Func<JsonSerializerSettings> defaultJsonConvertSettings = () =>
{
    return new JsonSerializerSettings
    {
        NullValueHandling = NullValueHandling.Ignore
    };
};
JsonConvert.DefaultSettings = defaultJsonConvertSettings;

You'll also need to add this line at the beginning of the file:

 

using Newtonsoft.Json;

Assuming I've understood the issue correctly, does this workaround do the trick?

Highlighted
Honor Student

Re: Zuora client generated code "csharp-dotnet2-client" does not return actual model.

Hi David,

 

Appreciate your reply. This works.

 

public ApiClient(String basePath = "https://rest.zuora.com")
        {
            BasePath = basePath;
            RestClient = new RestClient(BasePath);
            JsonConvert.DefaultSettings = () => new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
        }

I added into ApiClient constructor. 
Works!!!

Zuora Documentation

Re: Zuora client generated code "csharp-dotnet2-client" does not return actual model.

Hi Stanley,

 

That's great - thanks for confirming it works! Very happy to help out.

 

David