I'm new in the payment domain but would really like to get a good grip on what actions can be done and when they are available. I'm thinking about session initiation,authorization, cancellation, refund, reversal, chargeback and all other actions/states that are payment specific. For this a state diagram would be great, but I have not found any during my reading of the Adyen documentation or the rest of the internet. Is there one to be found, or do I have to make one myself and then ask for your input on its correctness?
Related
I've been testing out interacting with the XRP Ledger, coding in Python. I started coding some basic queries regarding the status of the XRP Ledger from scratch based on the XRPL documentation (available here) but then discovered XRPL-PY (I've reviewed the GitHub repo here and the documentation here) and have since been predominately using XRPL-PY to interact with the XRP Ledger given its general ease of use. I've been able to accomplish most of the basic types of interactions with the XRP Ledger one might want to do, including creating a wallet and submitting an offer to exchange one currency for another on the XRP Ledger (what I'll call an "Offer"). However, one point that I have been unable to figure out, whether by using XRPL-PY or interacting with the XRP Ledger directly, is how to determine when/whether a previously submitted Offer has been fully consumed (i.e., another transaction, or transactions, were submitted to the XRP Ledger that accepted my Offer such that it is no longer outstanding and the offered currencies were exchanged at the offered rate). This seems like a basic query that most people interacting with the XRP Ledger would want to be able to establish, but I haven't seen anything in the XRPL or XRPL-PY documentation explaining how to do it. My preference would be to be able to subscribe to updates from the XRPL Ledger such that it lets me know once my Offer has been partially or fully consumed, but if that's not possible I would like to at least be able to repeatedly query the status of my Offer from the XRP Ledger and know what will change in the response once my Offer has been partially or fully consumed. Any suggestions would be greatly appreciated.
It looks like you had your question answered on another channel so I will include this here just in case people will find this useful later. Cheers!
You have 3 options:
POLLING account_offers. You can use the sequence number to identify the offer
POLLING book_offer. You can use the "Account" and "Sequence" fields to identify the offer.
WS subscribing to "accounts" using the account you want to track. This is the most "complex" because you need to parse all the metadata for all validated transactions that involve the particular account but it's the best because it's asynchronous and via websocket.
Let me know if I am on the right train of thought. I'm currently building a dapp that will be based on my own parachain, and I was wondering if by adding this pallet, it would be a way to allow users in my dapp to pay for membership.
Obviously I would have to have some extrinsic functions that are exposed through my dapp so that when they click and pay for membership, in the runtime, the membership pallet will add that user as a member. Can anyone confirm my thoughts on this?
This leads up to another question. Should I just create a smart contract to handle membership logic and deploy it on edgeware or some other parachain that already exists?
obviously I would have to have some extrinsic functions that are exposed through my dapp so that when they click and pay for membership, in the runtime, the membership pallet will add that user as a member. Can anyone confirm my thoughts on this?
You can easily do this. pallet_membership is just a container for members. As you will find in the pallet_membership::Config, there are special origins that can be defined as those who have the authority to add or remove a member.
You need a new pallet that will handle the payment to join new members. Let's call this pallet_membership_payment. Once pallet_membership_payment has received the correct payment, it can call into pallet_membership::add_member with whatever origin is required to satisfy it. Not that even if the origin requirement of add_member is EnsureRoot, pallet_membership_payment can still practically get over it, if it is coded as such.
Should I just create a smart contract to handle membership logic and deploy it on edgeware or some other parachain that already exists.
The answer to this really depends on how much further logic does your application have next to handling this membership via fees. Also, it depends on the smart contract payment model (end user pays the fees) works for you If this is it, then it is pretty simple. You might have an easier time in a smart contract model. But, if you need certain optimisations, less fees, more performance etc. you will probably have to consider being your own (para)chain.
Here's an abstract question with real world implications.
I have two microservices; let's call them the CreditCardsService and the SubscriptionsService.
I also have a SPA that is supposed to use the SubscriptionsService so that customers can subscribe. To do that, the SubscriptionsService has an endpoint where you can POST a subscription model to create a subscription, and in that model is a creditCardId that points to a credit card that should pay for the subscription. There are certain business rules that say whether or not you can use said credit card for the subscription (expiration is more than 12 months away, it's a VISA, etc). These specific business rules are tied to the SubscriptionsService
The problem is that the team working on the SPA want a /CreditCards endpoint in the SubscriptonsService that returns all valid credit cards of the user that can be used in the subscriptions model. They don't want to implement the same business validation rules in the SPA that are in the SubscriptionsService itself.
To me this seems to go against the SOLID principles that are central to microservice design; specifically separation of concerns. I also ask myself, what precedent is this going to set? Are we going to have to add a /CreditCards endpoint to the OrdersService or any other service that might use creditCardId as a property of it's model?
So the main question is this: What is the best way to design this? Should the business validation logic be duplicated between the frontend and the backend? Should this new endpoint be added to the SubscriptionsService? Should we try to simplify the business logic?
It is a completely fair request and you should offer that endpoint. If you define the rules for what CC is valid for your service, then you should offer any and all help dealing with it too.
Logic should not be repeated. That tend to make systems unmaintainable.
This has less to do with SOLID, although SRP would also say, that if you are responsible for something then any related logic also belongs to you. This concern can not be separated from your service, since it is defined there.
As a solution option, I would perhaps look into whether I can get away with linking to the CC Service since you already have one. Can I redirect the client with a constructed query perhaps to the CC Service to get all relevant CCs, without actually knowing them in the Subscription Service.
What is the best way to design this? Should the business validation
logic be duplicated between the frontend and the backend? Should this
new endpoint be added to the SubscriptionsService? Should we try to
simplify the business logic?
From my point of view, I would integrate "Subscription BC" (S-BC) with "CreditCards BC" (CC-BC). CC-BC is upstream and S-BC is downstream. You could do it with REST API in CC-BC, or with a message queue.
But what I validate is the operation done with a CC, not the CC itself, i.e. validate "is this CC valid for subscription". And that validation is in S-BC.
If the SPA wants to retrieve "the CCs of a user that he/she can use for subscription", it is a functionality of the S-BC.
The client (SPA) should call the the S-BC API to use that functionality, and the S-BC performs the functionality getting the CCs from the CC-BC and doing the validation.
In microservices and DDD the subscriptions service should have a credit cards endpoint if that is data that is relevant to the bounded context of subscriptions.
The creditcards endpoint might serve a slightly different model of data than you would find in the credit cards service itself, because in the context of subscriptions a credit card might look or behave differently. The subscriptions service would have a creditcards table or backing store, probably, to support storing its own schema of creditcards and refer to some source of truth to keep that data in good shape (for example messages about card events on a bus, or some other mechanism).
This enables 3 things, firstly the subscriptions service wont be completely knocked out if cards goes down for a while, it can refer to its own table and work anyway. Secondly your domain code will be more focused as it will only have to deal with the properties of credit cards that really matter to solving the current problem. Finally if your cards store can even have extra domain specific properties that are computed and materialized on store.
Obligatory Fowler link : Bounded Context Pattern
Even when the source of truth is the domain model and ultimately you must have validation at the
domain model level, validation can still be handled at both the domain model level (server side) and
the UI (client side).
Client-side validation is a great convenience for users. It saves time they would otherwise spend
waiting for a round trip to the server that might return validation errors. In business terms, even a few
fractions of seconds multiplied hundreds of times each day adds up to a lot of time, expense, and
frustration. Straightforward and immediate validation enables users to work more efficiently and
produce better quality input and output.
Just as the view model and the domain model are different, view model validation and domain model
validation might be similar but serve a different purpose. If you are concerned about DRY (the Don’t
Repeat Yourself principle), consider that in this case code reuse might also mean coupling, and in enterprise applications it is more important not to couple the server side to the client side than to
follow the DRY principle. (NET-Microservices-Architecture-for-Containerized-NET-Applications book)
Having trouble with the PURCHASE_CANCELED error in Wallet for Digital.
A. I can successfully round-trip JWTs between
https://sandbox.google.com/checkout/customer/gadget/inapp/demo.html
and
https://developers.google.com/commerce/wallet/digital/docs/jwtdecoder
...of course I can, they're both Google tools.
B. I can successfully pass from PyJWT to the decoder, seems no info changes.
C. I can successfully pass from the demo to PyJWT, seems no info changes.
D. The request in the .buy() failure callback is correct.
This is extremely frustrating, to have no feedback from Google Wallet when it does PURCHASE_CANCELED.
I cannot make identical JWTs between PyJWT and the demo encoder. Even with exactly similar data in exactly the same order, the result varies at the end of the long string. Does this matter?
Is there any way of independently generating the signature (encoded) to verify against?
Does the order of keys in the object to encode matter?
Edit:
In the Order History, Wallet says "Google has sent the customer an order confirmation email." No emails arrive to my test buyer.
Also in the Order History, Wallet says "The customer's credit card was authorized for $3.00, and passed all risk checks". Looks promising.
I remember reading that, in the Sandbox, no banking or tax info is necessary. However, Google Books held me up for months on "selling" a $0 (free) book in Google Play due to lack of banking/tax information; without it, the book never made it through the approval process, no other explanation given. Does the Sandbox need even fake/placeholder information to allow .buy() transactions to proceed?
Flow is now working, postbacks are appearing at the server.
Estimated delay was 5-6 hours between sandbox setup and start of postback activity.
No changes made within sandbox tax/banking info.
We are trying out CQRS. We have a validation situation where a CustomerService (domain service) needs to know whether or not a Customer exists. Customers are unique by their email address. Our Customer repository (a generic repository) only has Get(id) and Add(customer). How should the CustomerService find out if the Customer exists?
Take a look at this blog post: Set based validation in the CQRS Architecture.
It addresses this very issue. It's a complex issue to deal with in CQRS. What Bjarte is suggesting is to query the reporting database for existing Customer e-mail addresses and issue a Compensating Command (such as CustomerEmailAddressIsNotUniqueCompensatingCommand) back to the Domain Model if an e-mail address was found. You can then fire off appropriate events, which may include an UndoCustomerCreationEvent.
Read through the comments on the above blog post for alternative ideas.
Adam D. suggests in a comment that validation is a domain concern. As a result, you can store ReservedEmailAddresses in a service that facilitates customer creation and is hydrated by events in your event store.
I'm not sure there's an easy solution to this problem that feels completely clean. Let me know what you come up with!
Good luck!
This issues does not have to be that complex:
Check your reporting store for customer uniqueness before submitting the UpdateCustomer command.
Add a constraint to your DB for uniqueness on email address. When executing the command, handle the exception and send a notification to the user using a reply channel. (hences never firing CustomerUpdated events to the reporting store.
Use the database for what it's good for and don't get hung up on ORM limitations.
This post by Udi Dahan http://www.udidahan.com/2009/12/09/clarified-cqrs/ contains the following paragraph:
"Also, we shouldn’t need to access the query store to process commands – any state that is needed should be managed by the autonomous component – that’s part of the meaning of autonomy."
I belive Udi suggested simply adding a unique constraint to the database.
But if you don't feel like doing that, based on the statement above, I would suggest just adding the "ByEmail" method to the repository and be done with it - but then again Udi would probably have a better suggestion..
Hope I am not too late...but we faced a similar situation in our project, we actually intercept the command executor and attach it with the set of rules created for that command, which in turn uses a query to fetch the data.
So in this case, We can have a class by the name, CustomerEmailMustBeUniqueRule which is fetched by the RuleEngine when the command "RegisterCustomerCommand" is about to be executed by RegisterCustomerCommandExecutor. This rule class has the responsibility to query the database to find if the email id exist and stop the execution by raising the invalid flag...