Just migrated to Stripe.com. I am creating a checkout session programmatically. See code snippet below. When I test, the User.Identity.GetUserId() comes back with a value and it is sent to stripe. However, when end user completes the payment, Stripe.com is not sending back the client_reference_id (it is null) in the event checkout.session.completed that I am listening to.
I get back my client_reference_id when I do payment links (send via querystring)
What am I doing wrong?
[HttpPost]
[AllowAnonymous]
public ActionResult SendToCheckout(ProcessPaymentViewModel model)
{
StripeConfiguration.ApiKey = _apiSecret;
var options = new SessionCreateOptions
{
ClientReferenceId = User.Identity.GetUserId(),
SuccessUrl = ConfigurationManager.AppSettings["BaseUrl"] + "/PaymentComplete",
CancelUrl = ConfigurationManager.AppSettings["BaseUrl"] + "/Subscribe",
LineItems = new List<SessionLineItemOptions>
{
new SessionLineItemOptions
{
Price = model.PriceId,
Quantity =long.Parse(model.Quantity)
},
},
Mode = "payment",
};
var service = new SessionService();
var session = service.Create(options);
return Redirect(session.Url);
}
reviewed stripe.com documentation. It appears I am setting it correctly. The other questions posted is one is really not answered and the other one says it should be in that webhook event. I dumped the values and it should client_reference_id: null
The code you shared looks correct and it's almost certain that you are not setting a value when you think you are.
The best path forward is to hardcode a value in your code and you should see that it works as expected and that the problem is the value you put in. What I would do is hardcode AAAA, confirm it's there, and then concat AAAA and the value in your variable and another string like AAAA-<userid>-BBBB and see that you get AAAA--BBBB because your string is null or empty.
This isn't a Stripe bug, that feature works as expected and is used widely but I've tested it quickly to confirm.
You can also look at the response on the Session creation after your code and just print session.ClientReferenceId and see that it's null right now.
Related
I am using a web API with ASP.NET Core MVC, entityframework and angular as the front-end.
In my angular application I have Stepper component https://material.angular.io/components/stepper
In the first step I want to fill out my form and as soon as I click next I want to create the task and on the second form I want to update the settings for that newly created task. However, I need to get the PK of the newly created task to update the settings on my second form.
There is an api call to create a new task in the tTask table in sqlserver.
This is my API Post Method.
[ResponseType(typeof(CreatingTaskModel))]
public IHttpActionResult PosttTask(CreatingTaskModel CreatingTaskModel)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var newtTask= new tTask
{
TaskName = CreatingTaskModel.TaskName,
TaskDescription = CreatingTaskModel.TaskDescription,
EmailSubject = CreatingTaskModel.EmailSubject,
EmailBody = CreatingTaskModel.EmailBody,
FK_TaskTeam = CreatingTaskModel.tTaskTeam.pk_TaskTeam,
Enabled = CreatingTaskModel.Enabled ? 1:0,
};
db.tTasks.Add(newtTask);
db.SaveChanges();
var pk = new {id = CreatingTaskModel.PK_Task};
return Ok("Success");
}
This is the submit code in angular :
onSubmit()
{
if(this.taskForm.valid)
{
this.service.createTask(this.taskForm.value).subscribe((data) => {
debugger;
console.log(data)
})
}
}
I saw that return Ok() in my webapi returns a message and I was thinking of sorting the tTask table by decending order of after the db.SaveChanges();
and returning the last item that it find and sending it back in the Ok(pk) and then casting that into an integer on my client-side and using that to get the data to update it.
What is the correct way to do this? Should it be done in sql or on the webapi?
This is what I ended up doing:
var newObject = new
{
id = newtTask.PK_Task,
message = "Success"
};
return Ok(newObject);
and on angular I have this:
onSubmit(){
if(this.taskForm.valid) {
this.service.createTask(this.taskForm.value).subscribe((data) => {
if(data.message){
if(data.message == "Success"){
this.getRecipentData(data.id);
this.AdditionalRecipientForm.controls['FK_Task'].setValue(data.id);
this.pk_Task = data.id;
}
}
debugger;
console.log(data)
})
}
It just doesn't seem practical to do this, but it does the job. What do you guys think? Should I maybe instead of going to the serve twice maybe after it goes to the done filling out both forms submit them both? Like call create method in my API and then call my second API to update the data the was submitted in the second form. I am just looking for ideas or most common practice for these types of situations.
After you've added it to the database and called db.SaveChanges, the key will be assigned to the object. So, after db.SaveChanges, you should just be able to simply reference newtTask.Id.
So I assume you manually assign the id of the new task via PK_Task = CreatingTaskModel.PK_Task, and that it's indeed this id that gets saved to the Db. Therefore the id column should not be autoincrementing.
If that's true you can, as Louis said before, simply return your object or only the id if you're concerned about bandwidth.
You can do return new OkObjectResult(pk); or just use the shorthand: return Ok(pk);, which will also return an OkObjectResult with the pk object as payload.
I've implemented a c# app which creates calendar events using the calendar API.
In order to keep the calendar in sync with our local db I've created a watch on the calendar. The following code does this and, as far as I can see, a watch is created.
Channel watchChannel = new Channel()
{
Id = ConfigurationManager.AppSettings["GOOGLE_CALENDAR_WATCH_NAME"],
Type = "web_hook",
Address = ConfigurationManager.AppSettings["GOOGLE_CALENDAR_SYNC_TRIGGER_CALLBACK_URL"],
Expiration = (unixTimestamp + NINETY_DAYS_IN_SECONDS) * 1000 //milliseconds
};
try
{
logger.Debug("Creating calendar watch with the name " +
ConfigurationManager.AppSettings["GOOGLE_CALENDAR_WATCH_NAME"] + " for calendar with id " + remoteCalendarId);
Channel returnChannel = service.Events.Watch(watchChannel, remoteCalendarId).Execute();
My problem is that the callback URL isn't getting called (i have confirmed ownership of the domain and authenticated it for the user, that shouldn't be the issue).
How do I debug this? Is there anywhere I can look at the attempts google is
making to call the callback URL?
I say that as far as I can see everything is created ok, but maybe I'm wrong, which property in the
returnChannel should I be looking at?
Is there any way to list all created watches/channels for a particular calendar? If so, which API is that exposed through?
04.04 - A bit more information:
These are the parameters set on the outgoing call (watchChannel) and return-object (returnChannel).
watchChannel
Address "https://a.domain.com/api/schedule/syncDbAndSchedule"
ETag = null
Expiration = 1491309746000
Id = "my_id_watch_dev"
Kind = null
Params__ = null
Payload = null
ResourceId = null
ResourceUri = null
Token = null
Type = "web_hook"
returnChannel
Address = null
ETag = null
Expiration = 1491309746000
Id = "my_id_watch_dev"
Kind = "api#channel"
Params__ = null
Payload = null
ResourceId = "t6uxfXzXXXXXXXXXXsC9ZEqMdzU"
ResourceUri = "https://www.googleapis.com/calendar/v3/calendars/a.domain.com_nsqpp2XXXXXX93olf0ul40sphg#group.calendar.google.com/events?maxResults=250&alt=json"
Token = null
Type = null
Looking at it again I've got a few more questions:
Can I be sure the above returned a HTTP-200 response? The client-libs seem to abstract away the actual request/response and I can't find any trace of it in the objects I'm looking at. As the 4xx responses I've gotten have been transformed into exceptions that's what I'd expect for any non-200 response but can I be sure of that?
Is there really no way to track the attempts google is making whilst calling the callback URL? Since there seems to be no way to get a hold of a created watch it kind of surprises me there is no GUI where I can track this. Makes hunting for errors really hard.
Code to authenticate
I use the following code to authenticate the system user and then make it act in the guise of a 'normal' non-system account (since a pure system-account seemed a tricky way to go if you actually wanted to look at the calendar too).
ServiceAccountCredential credential =
GoogleCredential.FromJson(GOOGLE_SYSTEM_USER_AUTH_INFORMATION)
.CreateScoped(Scopes)
.UnderlyingCredential as ServiceAccountCredential;
var userField =
typeof(ServiceAccountCredential).GetField("user", BindingFlags.NonPublic | BindingFlags.Instance);
userField?.SetValue(credential, GOOGLE_CALENDAR_USERNAME); //Act in the guise of the normal user GOOGLE_CALENDAR_USERNAME
service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
on a whim I visited the ResourceURI returned. It gives me
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
"extendedHelp": "https://code.google.com/apis/console"
}
],
"code": 403,
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup."
}
}
Is
this the status for the watch? If so, why didn't I get a 403 whilst creating it?
Am I really Unautenticated or is it just that my request through a browser is?
The callback url must be https (certificate) otherwise it will not be called!
I am trying to explain why a user was able to submit the same form details twice. At first, I was thinking that the submit button was pushed twice, this may still be the case.
When I checked the results in the database, I can see the same information has been entered twice, but also the same datetime stamp has been entered, down to the second. Surely it takes at least another second to push submit again if this is the case.
In addition after the survey is inputted and saved the user is redirected to a different page.
Why does this happen?
[HttpPost]
public ActionResult InputResult(SurveyViewModel model)
{
if (ModelState.IsValid)
{
Survey_Result InputResult = new Survey_Result();
InputResult.SurveyStatusID = model.SurveyStatusID;
InputResult.Q1DateCompleted = DateTime.Now;
InputResult.Q2 = model.Q2;
InputResult.Q3 = model.Q3;
InputResult.Q10 = model.Q10;
InputResult.Q11 = model.Q11;
InputResult.Q11Other = model.Q11Other;
InputResult.DateAdded = DateTime.Now;
InputResult.AddedBy = Convert.ToInt32(User.Identity.GetUserId());
_surveyService.AddSurvey(InputResult);
_surveyService.Save();
return RedirectToAction("Details", "Survey", new { id = model.SurveyStatusID, feedback = "InputComplete" });
}
return RedirectToAction("Details", "Survey", new { id = model.SurveyStatusID, feedback = "InputError" });
}
The code looks fine to me. If you have access to the user, you could pop Fiddler on it to see if it is posting data twice. If it doesn't happen all the time then its almost certainly user error IMHO.
If you don't have access to the client you could pop in a log entry on each post request or debug line if you are in a position to collect it on this server.
I had similar issues and client side javascript to disable the button on click did the trick for me.
Are you sure you need both AddSurvey and Save?
Remove save and retry.
I'm working on integrating PayPal into a client's ecommerce site. Using the sandbox, we got everything working fine. I now need to add in SetPaymentOptionsRequest to prevent the user from changing his shipping address (they enter it on our site, so they can't change it at PayPal due to different shipping costs calculated on our site). It appears to work fine, but I get a 3005 error when logging into the PayPal sandbox site to confirm the transaction. Below is the relevant code (C#):
public string MakeChainedPayment(params params) {
var request = new PayRequest {
requestEnvelope = new RequestEnvelope("en_us"),
actionType = "CREATE",
cancelUrl = this._cancelUrl,
currencyCode = this._currencyCode,
returnUrl = this._returnUrl,
ipnNotificationUrl = this._ipnNotificationUrl
};
// Some code to generate receivers, not important for this problem, I don't think
var response = this._paymentService.Pay(request);
switch (response.paymentExecStatus) {
// This always returns "CREATED", as I'd want, so good up to here.
case "CREATED":
// If I leave this code out, PayPal works fine, but I need
// this part to do the shipping address verification.
var p = new SetPaymentOptionsRequest();
p.senderOptions = new SenderOptions();
p.senderOptions.addressOverride = false;
p.senderOptions.shippingAddress = new ShippingAddressInfo {
// Setting from params: city, country, zip, state, street1, street2
};
p.payKey = response.payKey;
p.requestEnvelope = request.requestEnvelope;
SetPaymentOptionsResponse r = _paymentService.SetPaymentOptions(payOptsReq);
break;
// This always retuns r.error.Count = 0, r.responseEnvelope.ack = "SUCCESS",
// so I think I'm good to go.
}
if (this._useSandbox) {
return string.Concat("https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_ap-payment&paykey=", response.payKey);
}
return string.Concat("https://www.paypal.com/cgi-bin/webscr?cmd=_ap-payment&paykey=", response.payKey);
}
Paypal returns this message when your Paypal account's email address has not been verified. To verify your Paypal Email account, please follow the following steps:
Log into your Paypal Account. You should be in the “Overview” tab.
Click on your Email address, under “Business account overview”, you will be taken to a Web page listing your Paypal Email addresses.
Select your Primary Adress.
Click on the “Confirm” button.
Follow the rest of the Paypal instructions.
The problem was what I was passing in for the country; I was sending in "USA", and it should be "US".
I'm just getting into mvc 4 (and mvc in general) and am just wondering is this action code ok or should it be stripped down again?
[HttpPost]
public ActionResult Index(DashboardViewModel dbModel)
{
//retrieve latest resident order
var residentOrder = db.ResidentOrders.GetById(dbModel.ResidentOrderID);
if (residentOrder == null)
{
var order = db.Orders.GetById(dbModel.OrderID);
var user = db.Users.GetUserByUsername(User.Identity.Name);
residentOrder = new ResidentOrder()
{
CreatedDate=DateTime.Now,
LastUpdateDate = DateTime.Now,
Litres=0,
Customer = user
};
order.ResidentOrders.Add(residentOrder);
db.Commit();
}
//check to see if value has changed
if (!dbModel.ResidentLitresOrdered.Equals(residentOrder.Litres))
{
//get new ordered value
residentOrder.Litres = dbModel.ResidentLitresOrdered;
db.Commit();
//send an email just to notify in writing of the change.
SendOwnOrderQtyUpdateNotification();
}
return View(dbModel);
}
Basically if a resident order doesnt exist then we create one, this is the only place in the system where this would need to happen.
Should I still be stripping that code out into my repositories?
db is my IUnitOfWork btw
I would recommend that you create a "repository" to hide the details from the Controller action.
An "Upsert" method would allow this to be clearly and elegantly implemented hiding the details from the controller.