Creating Subscription payments using PayPal SDK with .NET - c#

I have found this code on the following website:
https://devtools-paypal.com/guide/recurring_payment_ec/dotnet?interactive=ON&env=sandbox
The code is as follows:
SetExpressCheckoutRequestDetailsType ecDetails = new SetExpressCheckoutRequestDetailsType();
ecDetails.ReturnURL = "https://devtools-paypal.com/guide/recurring_payment_ec/dotnet?success=true";
ecDetails.CancelURL = "https://devtools-paypal.com/guide/recurring_payment_ec/dotnet?cancel=true";
ecDetails.PaymentDetails = paymentDetails;
BillingCodeType billingCodeType = (BillingCodeType)EnumUtils.GetValue("RecurringPayments", typeof(BillingCodeType));
BillingAgreementDetailsType baType = new BillingAgreementDetailsType(billingCodeType);
baType.BillingAgreementDescription = "recurringbilling";
ecDetails.BillingAgreementDetails.Add(baType);
SetExpressCheckoutRequestType request = new SetExpressCheckoutRequestType();
request.Version = "104.0";
request.SetExpressCheckoutRequestDetails = ecDetails;
SetExpressCheckoutReq wrapper = new SetExpressCheckoutReq();
wrapper.SetExpressCheckoutRequest = request;
Dictionary<string, string> sdkConfig = new Dictionary<string, string>();
sdkConfig.Add("mode", "sandbox");
sdkConfig.Add("account1.apiUsername", "jb-us-seller_api1.paypal.com");
sdkConfig.Add("account1.apiPassword", "WX4WTU3S8MY44S7F");
sdkConfig.Add("account1.apiSignature", "AFcWxV21C7fd0v3bYYYRCpSSRl31A7yDhhsPUU2XhtMoZXsWHFxu-RWy");
PayPalAPIInterfaceServiceService service = new PayPalAPIInterfaceServiceService(sdkConfig);
SetExpressCheckoutResponseType setECResponse = service.SetExpressCheckout(wrapper);
This first part of the code is responsible for creating a PayPal billing agreement on basis which is specified in the parameters of the code.
The call then at the end returns a string as following:
https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-4SD42613U5111594L
This takes the user to the paypal site to confirm the billing agreement and the user is then returned to my website.
Then to create a recurring payments profile associated with the billing agreement, which was created using the SetExpressCheckout call, make a CreateRecurringPaymentsProfile API call with the token you got in SetExpressCheckout API response and the billingAgreementDescription used in SetExpressCheckout API request.
The code looks as following:
CreateRecurringPaymentsProfileRequestType createRPProfileRequest = new CreateRecurringPaymentsProfileRequestType();
CreateRecurringPaymentsProfileRequestDetailsType createRPProfileRequestDetails = new CreateRecurringPaymentsProfileRequestDetailsType();
createRPProfileRequestDetails.Token = "EC-4SD42613U5111594L";
createRPProfileRequest.CreateRecurringPaymentsProfileRequestDetails = createRPProfileRequestDetails;
RecurringPaymentsProfileDetailsType profileDetails = new RecurringPaymentsProfileDetailsType("2016-010-31T00:00:00:000Z");
profileDetails.RecurringPaymentsProfileDetails = profileDetails;
int frequency = 10;
BasicAmountType paymentAmount = new BasicAmountType((CurrencyCodeType)EnumUtils.GetValue("USD", typeof(CurrencyCodeType)), "1.0");
BillingPeriodType period = (BillingPeriodType)EnumUtils.GetValue("Day", typeof(BillingPeriodType));
BillingPeriodDetailsType paymentPeriod = new BillingPeriodDetailsType(period, frequency, paymentAmount);
ScheduleDetailsType scheduleDetails = new ScheduleDetailsType();
scheduleDetails.Description = "recurringbilling";
scheduleDetails.PaymentPeriod = paymentPeriod;
profileDetails.ScheduleDetails = scheduleDetails;
CreateRecurringPaymentsProfileReq createRPProfileReq = new CreateRecurringPaymentsProfileReq();
createRPProfileReq.CreateRecurringPaymentsProfileRequest = createRPProfileRequest;
Dictionary<string, string> sdkConfig = new Dictionary<string, string>();
sdkConfig.Add("mode", "sandbox");
sdkConfig.Add("account1.apiUsername", "jb-us-seller_api1.paypal.com");
sdkConfig.Add("account1.apiPassword", "WX4WTU3S8MY44S7F");
sdkConfig.Add("account1.apiSignature", "AFcWxV21C7fd0v3bYYYRCpSSRl31A7yDhhsPUU2XhtMoZXsWHFxu-RWy");
PayPalAPIInterfaceServiceService service = new PayPalAPIInterfaceServiceService(sdkConfig);
CreateRecurringPaymentsProfileResponseType createRPProfileResponse = service.CreateRecurringPaymentsProfile(createRPProfileReq);
A response will be returned containing PROFILEID and ACK values:
PROFILEID=I-0H1CDRF2NEWB&PROFILESTATUS=ActiveProfile&TIMESTAMP=2016-10-31T15:56:13Z&CORRELATIONID=a5fcc91e86a24&ACK=Success&VERSION=104.0&BUILD=24616352
Once that is finished, I store hte ProfileID parameter into my DB so that I can handle the subscriptions for the future...
My question here is: how do I manage the subscriptions on monthly/yearly basis (depending how the user decides that he will pay monthly or yearly)?
There are couple of scenarios here that I'm thinking of:
What if user cancels the billing agreement via paypal ? Should I then check the subscription status upon every user login ?
Billing on the PayPal's side is probably done automatically , or do I have to create a payment request somehow every 1 month / 1 year in order to charge the user for using premium services on my website???
This is all still very confusing for me since I'm encountering this sort of problem for the first time since I started to do coding...
Can someone help me out?

Related

Stripe; how to get subscriptionId when creating a customer with a new subscription

I'm creating a new customer and adding them to a subscription in one call like so:
StripeConfiguration.SetApiKey(StripeData.ApiKey);
var customerService = new CustomerService();
var myCustomer = new CustomerCreateOptions
{
Email = stripeEmail,
Source = stripeToken,
Plan = StripeData.MonthlySubscriptionPlanId
};
Customer stripeCustomer = customerService.Create(myCustomer);
Then I used to be able to do this:
myLocalUser.StripeCustomerId = stripeCustomer.Id;
myLocalUser.StripeSubscriptionId = stripeCustomer.Subscriptions.Data[0]?.Id;
But now the API isn't returning the customer's subscriptions so the second line fails
I'm now having to call the API again with this ugly code to get the customer's subscriptionId:
if (stripeCustomer.Subscriptions != null)
{
user.StripeSubscriptionId = stripeCustomer.Subscriptions.Data[0]?.Id;
}
else
{
//get subscriptionId
var cust = customerService.Get(stripeCustomer.Id, new CustomerGetOptions
{
Expand = new System.Collections.Generic.List<string> { "subscriptions" }
});
if (cust.Subscriptions.Any())
{
stripeSubscriptionId = cust.Subscriptions.First().Id;
}
}
CustomerService.Create() doesn't have the same Expand parameter option that the Get() method does...
This is expected, as subscriptions are no longer included by default on a customer object unless you expand them since API version 2020-08-27.
Creating a customer with a source and plan is still possible (although not the recommended integration path anymore since you might run into problems with 3DS and tax rates), although since you are on a newer API version you won't get the subscriptions list back. If you can you should update to creating subscriptions via their own API.
If you however still want to use this old integration path, you can still get the subscriptions back in the customer create call, you just need to expand the subscriptions on creation:
var customerService = new CustomerService();
var myCustomer = new CustomerCreateOptions
{
Email = stripeEmail,
Source = stripeToken,
Plan = StripeData.MonthlySubscriptionPlanId
};
myCustomer.AddExpand("subscriptions");
Customer stripeCustomer = customerService.Create(myCustomer);

How to cancel a customer's subscription in Stripe.net - they update too often

I first used stripe back in 2015. It was easy, then I figured it out (kind of) in 2018/19. But now I'm trying again on an older project and am completely stuck. I'm using checkout.js because I can no longer figure out managing the card, and I can create a customer, add them to a subscription, and even retrieve the customer id. I can pull back customer details, but I can't figure out how to update their subscritpion - specifically how to cancel it. I've updated the metadata aspect after trying for a while on understanding the API, but it doesn't seem to affect the next invoice. Here is my current approach:
StripeConfiguration.SetApiKey("testkey");
var customers = new CustomerService();
var charges = new ChargeService();
var userId = User.Identity.GetUserId();
var user = db.Users.Single(x => x.Id == userId);
var customer = customers.Get(user.CustomerId);
var sub = customer.Subscriptions.FirstOrDefault();
sub.CancelAtPeriodEnd = true;
Somehow I need to update here??
Then this is back to where I just clear out my user.
user.CustomerId = null;
user.Paid = false;
It's not too pretty right now, but I just don't get this.
Another approach is this:
var service = new SubscriptionService();
var options = new SubscriptionUpdateOptions {
CancelAtPeriodEnd = true,
};
Subscription subscription = service.Update("subid", options);
But I don't understand how this ties to the customer and their customerid.
Do you try deleting the custumer? or is not your objective delete it?
StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc";
var service = new CustomerService();
service.Delete("cus_H01wAPhnLalFWf");
In the API ref guide says: Also immediately cancels any active subscriptions on the customer

Expanding a Source object in a Stripe API call to StripeBalenceService doesn't return any customer info

I'm making a c# call to the Stripe.net API to fetch a balance history for a connected account. I'm trying to expand on the balance transaction object to see where the charge is coming from (ex. the customer who made the charge) as all the charges to connected accounts on my platform are from charge objects with a destination property to the connected account.
Here is my code and a screenshot of what the expanded source looks like, but think I should see a charge id or a customer or something refering me to the initial customer somewhere, but I don't...
var balanceService = new StripeBalanceService();
balanceService.ExpandSource = true;
var list = new List <string> () {
"data.source.source_transfer"
};
StripeList <StripeBalanceTransaction> balanceTransactions
= balanceService.List(
new StripeBalanceTransactionListOptions() {
Limit = 20,
Type = "payment",
Expand = list
},
new StripeRequestOptions() {
StripeConnectAccountId = accountId
}
);
foreach(var transaction in balanceTransactions) {
var test = transaction;
}
I feel like I should see a charge id (ex. ch_xxx) or a Customer value (which is null) all I see of any relevance is a payment id (ex. py_xxx)
It is possible to get the charge object(ch_xxx), it is just a little involved!
As you are using destination charges, the charge(ch_xxx) takes place on the platform account, and then a transfer(tr_xxx) is made to the connected account. That transfer creates a payment(py_xxx) on the connected account, which results in a balance transaction(txn_xxx).
As your code expands the source of those balance transactions, you get the payment(py_xxx). The payment is equivalent to a charge, so it has a source_transfer field. You can expand this field also! This will give you the transfer object(tr_xxx). Finally, the transfer has a source_transaction field, and this can be exapanded to give the original charge(ch_xxx)!
Putting that all together, you will want to expand on "data.source.source_transfer.source_transaction".
If you use a Stripe library in a dynamic language you can see this in action ... unfortunately, stripe-dotnet has an open issue right now which means that you can not do this directly. Instead, you will need to make the API calls manually by calling the various Retrieve functions on the IDs, instead of doing a single expansion. It would look something like this:
var paymentId = transaction.Source.Id;
var chargeService = new StripeChargeService();
var payment = chargeService.Get(
paymentId,
new StripeRequestOptions()
{
StripeConnectAccountId = accountId
}
);
var transferService = new StripeTransferService();
transferService.ExpandSourceTransaction = true;
var transfer = transferService.Get(payment.SourceTransferId);
var charge = transfer.SourceTransaction;
Console.WriteLine(charge.Id);

GetRecords that are approved in ServiceNow API

ServiceNow - GetRecords
Code:
var proxy = new ServiceNow_dmn_demand()
{
Url = "https://<instance>.service-now.com/dmn_demand.do?SOAP",
Credentials = new NetworkCredential("username", "password")
};
var objRecord = new Service.getRecords
{
// Here, I want to filter the records that are approved..
};
var recordResults = proxy.getRecords(objRecord);
I am getting all the records.
I want to get the records that are only approved. But I don't know the
exact field name used to filter the Approved records.
You are looking for the state field, and specifically where state=8. This table extends the Task where the State field is defined. If you look at the choice list for that state field on task you will see value=8, has label of approved. If you query for only dmn_demand records where state = 8 this should give you what you want. Also consider using the ServiceNow REST API and the ServiceNow REST API Explorer (in Fuji release) to help you build and test these requests.

ASP.NET MVC C# PayPal Rest API - UNAUTHORIZED_PAYMENT

I'm trying to integrate the paypal rest api to my web application. After digging through all available sources I'm stuck.
I'm using the paypal rest api example from here:
GitHub-PayPal-DotNet-Sample
I updated the nuget to the latest sdk version and replaced the cliendId and secret with my own live keys.
Now my problem is, always I choose "credit_card" I get an 401 error response:
{
"name": "UNAUTHORIZED_PAYMENT",
"message": "Unauthorized payment",
"information_link": "https://developer.paypal.com/webapps/developer/docs/api/#UNAUTHORIZED_PAYMENT",
"debug_id": "1d25a990be5db"
}
I set the currency to "CHF" (application runs in Switzerland) and the amount to "0.05" for testing purposes. I also retrieve a valid access token!
Tried various credit cards some belongs to my merchant account some not, still the same error.
With the option "paypal" it seems to work, but I want to offer credit cards directly within the application.
Is something not available in Switzerland? Any suggestions for this problem? Did I overlook something?
Thanks in advance!
Sample Code:
Payment pay = null;
Amount amount = new Amount();
amount.currency = "CHF";
amount.total = "0.05";
Transaction transaction = new Transaction();
transaction.amount = amount;
transaction.description = orderDescription;
List<Transaction> transactions = new List<Transaction>();
transactions.Add(transaction);
FundingInstrument fundingInstrument = new FundingInstrument();
CreditCardToken creditCardToken = new CreditCardToken();
creditCardToken.credit_card_id = GetSignedInUserCreditCardID(email);
fundingInstrument.credit_card_token = creditCardToken;
List<FundingInstrument> fundingInstrumentList = new List<FundingInstrument>();
fundingInstrumentList.Add(fundingInstrument);
Payer payer = new Payer();
payer.funding_instruments = fundingInstrumentList;
payer.payment_method = paymntMethod.ToString(); //credit_card
Payment pyment = new Payment();
pyment.intent = "sale";
pyment.payer = payer;
pyment.transactions = transactions;
pay = pyment.Create(AccessToken);
return pay;
Per this Direct card payment is only supported in the US, UK (look at the page for further requirements for UK).

Categories