I have upgraded the Stripe.net to the latest version which is 20.3.0 and now I don't seem to find the .Last4 for the credit card. I had the following method:
public void CreateLocalCustomer(Stripe.Customer stipeCustomer)
{
var newCustomer = new Data.Models.Customer
{
Email = stipeCustomer.Email,
StripeCustomerId = stipeCustomer.Id,
CardLast4 = stipeCustomer.Sources.Data[0].Card.Last4
};
_dbService.Add(newCustomer);
_dbService.Save();
}
But now the stipeCustomer.Sources.Data[0].Card.Last4 says 'IPaymentSource' does not contain a definition for 'Card'. Does anyone know how I can get the card details now? The flow is that I create the customer by passing the Stripe token to Stripe, then I get the above stripeCustomer. So I expect it to be somewhere in that object. But I can't find it. The release notes can be found here.
Thank you.
In the old world of Stripe, there only used to be one type of payment method you could attach to a Customer; specifically, Card-objects. You would create a Card-object by using Stripe.js/v2 or the Create Token API Endpoint to first create a Token-object and then attach that token to a Customer-object with the Create Card API Endpoint.
Once Stripe expanded to support a number of other payment methods though, Stripe built support for a new object type that encapsulated a number of payment methods (including credit cards) called Source-objects. A Source-object is created either by using Stripe.js/v3 or the Create Source API Endpoint. It can also be attached to a Customer-object in much the same way as the Card-objects mentioned above, except they retain their object type. They're still a Source. You use the Attach Source API Endpoint to do this (that is notably identical to the Create Card API Endpoint mentioned above).
What I'm getting at here, is there are now two different object types (or more) that you can expect to see returned in the sources-array (or Sources in .NET). All of these methods though inherit from the IPaymentSource-interface. So if you know you have a Card-object getting returned, you can simply cast the returned object to the Card-class.
Something like this should get you going:
CardLast4 = ((Card) stipeCustomer.Sources.Data[0]).Last4
You can see what I mean by inheritance by looking at this line in the Card-class file:
https://github.com/stripe/stripe-dotnet/blob/master/src/Stripe.net/Entities/Cards/Card.cs#L7
Good luck!
As of Stripe.net.21.4.1, this is what works:
var chargeService = new ChargeService();
var charge = chargeService.Get(id);
CardLast4 = ((Card)charge.Source).Last4;
It's getting hard not to panic when code breaks because of all the micro-changes Stripe makes.
So after debugging, it looks like the Data[0] needs to be cast as Card to get the card.
So it will be CardLast4 = ((Card)stipeCustomer.Sources.Data[0]).Last4.
Related
does anyone know how to create a secure in-game NFT mint? I think if we gave permission to users to create an NFT (this is the idea of the game - to assemble an NFT from different parts), it would be vulnerable because you can insert your own image URL into the function. I thought a mint function that can be used only by a game contract with the require(somePartsAmount), would it be secure?
Something like this:
function awardItem(address player, string memory tokenURI)
public
onlyGame
returns (uint256)
{
require(somePartsAmount);
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(player, newItemId);
_setTokenURI(newItemId, tokenURI);
return newItemId;
}
How to be with the presale mint, because we can't check parts here and creating by owner is too expensive?
Usually, you won't want to give users the opportunity to set a custom token URI to an nft. Thus, I would suggest making all the URI things in another function maybe. For you to have, let's say, 1000 minteable random nfts, you would first need 1000 tokenURIs for those nfts to have information attached to, and then you would have to use the default getTokenURI function which returns the base token URI you specify when creating the smart contract and just adds the nft id to the end of it.
So in the documentation, it says if you want to get tasks with immutable id instead of normal one just add a header 'Prefer: IdType="ImmutableId"'. I've done that but it still returns tasks with normal ID.
It works fine when I try it with outlook events and if I try to get outlook task by ID (get single task instead of listing all). But as soon as I try getting all tasks with immutable id it doesn't work. It doesn't say any error it just returns the data but with the normal id.
Also, I know that outlook tasks API is getting deprecated but todo list API is not going to cut it right now and I've already tried it - there is no way to retrieve any form of immutable ids, just normal ones.
This is the code I use to retrieve all tasks (list all tasks) in NodeJS:
let response = await client
.api('/me/outlook/tasks?$top=25000')
.header("Prefer", "IdType=\"ImmutableId\"")
.header('Prefer', `outlook.timezone="${timeZone}"`)
.version('beta')
.get();
It is very weird because when trying to get one specific task by ID and setting prefer id type header, it works.
Anyway here is how requests look:
LIST OUTLOOK TASKS (GET ALL OUTLOOK TASKS)
GET https://graph.microsoft.com/beta/me/outlook/tasks
GET ONE SPECIFIC TASK VIA ID
GET /me/outlook/tasks/{id}
HEADER FOR GETTING IMMUTABLE IDS INSTEAD OF NORMAL ONES
Prefer: IdType="ImmutableId"
POTENTIONALLY HELPFUL
This is the code I use to retrieve all events with Immutable ID's (this works compared to tasks)
let response = await client.
api('/me/calendar/events?$top=25000')
.header('Prefer', `outlook.timezone="${timeZone}"`)
.header("Prefer", "IdType='ImmutableId'")
.get();
MS Graph official documentation: How to retrieve a list of outlookTasks
MS Graph official documentation: outlookTask resource type
MS Graph official documentation: event resource type
MS Graph official documentation: Get immutable identifiers for Outlook resources
Okay, so I've found the solution and it's just ridiculous. If any MS Graph SDK developers see this please fix it.
Instead of this:
let response = await client
.api('/me/outlook/tasks?$top=25000')
.header("Prefer", "IdType=\"ImmutableId\"")
.header('Prefer', `outlook.timezone="${timeZone}"`)
.version('beta')
.get();
You MUST do this:
let response = await client
.api('/me/outlook/tasks?$top=25000')
.header("Prefer", `IdType="ImmutableId", outlook.timezone="${timeZone}"`)
.version('beta')
.get();
I guess setting the second Prefer header overrides the first one and consequentially only the second one is sent. Unfortunately, I've discovered this right after I implemented the solution via OpenTypeExtension.
in Stripe version 2020-03-02 I was able to retrieve a subscription and its associated credit_card in one go like this:
stripe_subscription = Stripe::Subscription.retrieve({:id => stripe_subscription_id, :expand => [:customer]})
stripe_customer = stripe_subscription.customer
stripe_credit_card = stripe_customer.sources.data.first
In version 2020-08-27 this seems no longer possible since Stripe won't recognise the sources attribute on customer.
So how can I retrieve a subscription and its credit card with one request only?
Since sources on Customer is not included by default, you have to explicitly include it when you expand the related properties. Your code would look like this:
stripe_subscription = Stripe::Subscription.retrieve({
id: stripe_subscription_id,
expand: ['customer.sources'],
})
stripe_customer = stripe_subscription.customer
stripe_credit_card = stripe_customer.sources.data.first
The expand feature is quite powerful and lets you expand multiple separate properties or chain expansion like we did above. I recommend reading the detailed documentation that Stripe shipped.
I've got a question regarding outside-aggregate validation.
In our domain partner can place orders that contain certain products (1).
Once order is placed (2) he can mark it as paid (3) in our system.
Once order is marked as paid (4) we assign licences to products in external library service (5).
Once we know licences are assigned (6) we close entire saga.
Here's a small drawing illustrating the process:
At this moment besides commands, command handlers and events there are two domain classes that are involved in entire process:
Order aggregate containing business logic
Order saga coordinating entire process and assigning licences
Now, there is one invariant that is not modelled in this process yet - before we mark order as paid we have to check if user does not already have particular licence assigned. We get this from library service as well.
Where would you put this validation? Command handler? Wrap Order in some domain service? Pass some validator to Order constructor?
class Order
{
public function __construct(OrderValidator $validator)
{
if (!$validator->isValid($this)) {
throw new \DomainException();
}
// else proceed
}
}
class OrderValidator
{
private $libraryServiceClient;
public function isValid(Order $order)
{
// check licence using $libraryServiceClient
}
}
As far as I understood the problem is in step 3 (Mark order as payed). In this step we need a user (let's call it payer) that marks the order as payed. So when creating this payer object (using factory maybe) we need to know if he is allowed to mark an order as payed. In order to get this information a call should be made to the external library.
What I suggest is to have an application service that have ->markOrderAsPayed($orderId, $payerUserId)
This method will make a call to 2 domain services. One for getting the payer and one for marking the order as payed.
$payer = $this->payerService->getPayer($payerUserId);
$this->orderService->payOrder($orderId, $payer);
In the getPayer() function you should make a call to the external library to know how many licences the payer have.
I hope this will be helpful, it is just based on what I understood from the questions and comments.
Is it possible to tell the country associated with the current user's account with the iOS Spotify SDK? How? I have not been able to find anything in the docs.
(I'd like to get the ISO 3166-1 alpha-2 country code so that another (unauthenticated) user can do searches with the web api and only find tracks that we will ultimately be able to play using the authenticated user that is using the SDK.)
Found it. It is available from the territory field of the SPTUser object. Here is how you might get it after having logged in and received a session object, example code in Swift:
SPTUser.requestCurrentUserWithAccessToken(session.accessToken) { error, object in
guard let user = object as? SPTUser,
territory = user.territory else {
print("Could not get territory, error: \(error)"
return
}
print(territory)
}
However, you will get nil values for the territory unless you have included SPTAuthUserReadPrivateScope in requestedScopes when setting up your SPTAuth object.