The transaction notifications sent by PayPal will slightly change. We need to adapt our application to be able to process them. Please refer to the [investigation documentation](https://docs.google.com/document/d/1UzOKLG9mk9kWO3wRKZKGBMevnVJc3qdVYNNY9nb-u8o/edit#heading=h.qeqkx356gbyr) for more details.
**Acceptance Criteria**
- Payment notifications for one-time payments (from the legacy payment URLs) can be processed by our application.
- Payment notifications for recurring payments (both from legacy and API) can be processed by our application.
**Implementation Notes**
- ~~The transaction types (`txn_type`) for recurrring payments will be:~~
- `recurring_payment_profile_created` (you can ignore this, it might get relevant later when we handle memberships)
- `recurring_payment`
- The transaction type (`txn_type`) for recurrring payments will be `cart`
- ~~The Fundraising Application needs to be changed to handle those new transaction types.~~
- The notification `recurring_payment_profile_created` should be accepteCreate a new service class (e.g. `ConfirmationUseCaseDispatcher`) for looking up donation/membership ID and type using IPN data: It should look at the transaction type to determine the name of the ID field (`recurring_payment_id` for `recurring_payment`, `txn_id` for `cart` ), use `payment_paypal_identifier` to get a payment id, but ignored for donation payments.`payment_id` field in donation and membership tables to get to the type (donation/membership) and the entity id. Create a matching use case:
- ~~Deploy the changed application to test and make a payment. Wait for the IPN to arrive~~- throw a "not implemented" exception for memberships
- ~~Look at the paypal.log data for a recurring payment - it should contain a `recurring_payment_id` that will allow us to determine if a recurring payment is for a membership or a donation.~~ - Prepare the `cart` case, in the service class. It won't do anything yet, but we can use the code when we implement {T344839}
- ~~look at the paypal.log for a one-time payment - it should contain a some id (referenced as `txn_id` in the following steps) that will allow us to match the payment with a donation.~~ - Do the current lookup of the donation (by Id) for all other `txn_type` values
- Check if the `txn_type` (for the values outlined above) that indicates that the IPN was issued from an API-Generated payment. if noonstruct the use cases with a "lenient" authorizer implementation that always returns `true` for `systemCanModifydonation`: You can ignore the `updateToken`, we have other means to make the end point secure and if the donation/membership doesn't exist, you can use the donation ID and security token from the `custom` fielduse case will throw an exception anyway
If the comes from the API, you need to look for a (`PaypalOrder` or `PaypalSubscription` (see T343846) with the right external id (doing a UNION select of the membership and donation table to find out what the payment is for). Create a new service class for this - it should receive the IPN data, look at the transaction type to determine the name of the ID field (`recurring_payment_id` for `recurring_payment`, `txn_id` for `cart` ) , request membership id and donation id from the database and return a use case with a "lenient" authorizer implementation that always returns `true` for `systemCanModifydonation`.
- Add test cases in `HandlePayPalPaymentNotificationRouteTest` that check the new payment data
- `recurring_payment` & matching `recurring_payment_id` for donations should be handled
- `recurring_payment` & non-matching `recurring_payment_id` should be dropped (and logged)
- `cart` without `custom` field and matching `txn_id` field should be handled
- `cart` without `custom` field and non-matching `txn` field should be dropped (and logged) - TODO discuss timing issues, if the lookup fails, we may wait for a few seconds and try again. This is because the flow be: a) call "capture payment" PPL API, get transaction id b) write transaction Id to database. The call to the API might trigger the IPN request before we had a chance to write to the DB. A highly unlikely case, but should still be considered.