Skip to content
This repository has been archived by the owner on Feb 2, 2022. It is now read-only.

WIP - One off charges #208

Closed
wants to merge 1 commit into from
Closed

WIP - One off charges #208

wants to merge 1 commit into from

Conversation

jelleroorda
Copy link
Contributor

This pull request closes #42.

There are a few things that still need to be done, and on which I would appreciate your input (@sandervanhooft).

Order items "on the tab" collision (?) with Subscription order items.

Currently, because of the nature of the subscription billing implementation, the 'open tab' may collide with subscription billing.

Example 1: calling $user->invoice() may end up invoicing subscription items if they are due for processing (could be the intended functionality?).
Example 2: php artisan cashier:run will invoice the items that we put on the tab, once they are due for processing.

If we intend to split apart subscription billing and one off payments, we can add an extra table tab_items that simply points to the id of an order item that is supposed to be on the tab. After that we can add two scopes onTheTab and forSubscriptions (naming up for discussion of course), and add the forSubscriptions scope to Cashier::run, as well as the onTheTab scope to the invoice method.

My assumption was/is that you would prefer not to split this apart, since it could be nice if a developer can put an extra item on the customers next bill (complementary to the fee for the subscription).

In this case we would need to document this properly, and in my opinion also write some extra tests that do some checking on the aforementioned scenario (subscription + one off payment complimentary usage).

Double checking the payment flow for one off payments

Though this is pretty obvious, you may want to double check if the one off payment flow that is implemented is correct. A quick summary:

Scenario 1:

  • Customer has a valid mandate
  • One off payment initiated by developer
  • Prevent if there are no order items that are due for processing
  • We create an invoice + process the payment

Scenario 2:

  • Customer doesn't have a valid mandate
  • One off payment initiated by developer
  • Prevent if there are no order items that are due for processing
  • We create a payment at Mollie, and redirect the customer to the checkout
  • Mollie calls our webhook.
    • if successful we create an order. (OrderPaymentPaid event)
    • if failed we don't create an order, so the tab stays open. (OrderPaymentFailed event)

This flow is quite the same as the "first payment" flow, except the fact that we are creating a "one off payment", which means we don't create a mandate in the process.

Something you will notice is that the "one off payment flow" is not using/hooking onto the Actions that are currently a feature for subscriptions. This was done on purpose, since I couldn't think of a scenario where you would want to do "anything fancy" with a one off payment. This also means that instead of storing actions in the Mollie Payment metadata, we are simply storing the order items. If someone can think of a valid reason to introduce the extra layer of complexity (the actions), we could revisit this implementation.

Double check the written tests

I'm not completely up to speed with your usual event dispatching for example, in the end I haven't used this package since 1.0 because there were no "one off payment" possibilities, which was my main use case in the application I was building. Kindly check if the tests are up to par, and if they need to be improved/extended.

Notes

  • The Laravel\Cashier\SubscriptionBuilder\RedirectToCheckoutResponse class has been reused (for developer friendliness), even though the namespace is now kind of weird; maybe we should flag this as something that can be improved in V2? (since it's a breaking change to move it to a different namespace)

  • Instead of using get_class($user) I used $user->getMorphClass(), which supports Laravels MorphMap (I noticed later you used get_class()). You could see this as a breaking change. If a developer has defined a morph map for their User model, it will now use the defined string by the developer instead of the fully qualified name of the User model (though chances are probably very low the generic developer is using this [this is an assumption though :)]). I noticed this later, as well as the assumption we're currently making that the user will always have an id column ($owner->id calls). We should replace this with $owner->getKey() instead in the future, so we support different primary key names. Let me know what your thought are on the above.

To do's

  • Add 2 extra variables to the phpunit.xml for usage in ManagesInvoiceTest.php, since one off payments have a different Mollie Payment metadata (they use the order items, not the actions after all.
  • (?) Might as well create a simply "entrypoint" for developers, from where they can run 1 test, and copy paste all the necessary Mollie id's to their phpunit.xml. This will (in my opinion) greatly improve onboarding of developers for pull requests (perhaps other pull request?).
  • Change ->getMorphClass() calls to get_class.
  • (?) Someone will need to add some extra tests for one off payment + subscription complimentary usage.

Let me know your thought on this so far.

@sandervanhooft
Copy link
Collaborator

Relates to #40 and #190 (MorphMap)

@sandervanhooft
Copy link
Collaborator

Regarding the testability for contributors, I agree that it could be simplified/easier to get started. Also see the discussion here.

@sandervanhooft
Copy link
Collaborator

First impressions:

  • I'm surprised by the high quality of this PR, a lot of thinking went into this. Big thanks!
  • there's still some cases that we'll need to cover (i.e. optionally create and store a new mandate, what if there's no next payment/subscription scheduled). I'll get back to you on this.
  • I like the "keeping a separate tab" idea. It's what I had in mind when designing this package. Having the Orders and OrderItems for the actual processing of payments, generating receipts etc.. They were designed to support any kind of "Orderable" item (subscription, one-off, ...). The only thing that is conceptually limiting this issue and for example multiplan subscriptions, is not having a dedicated BillingCycle. It's currently integrated with the Subscription. (For now, let's keep it that way ;) ).
  • The morphability is something I have to dive into. I like how Spatie has been doing this using configs and service providers. But my knowledge may be outdated on this part.

I highly appreciate this contribution and will be looking into this. It will be a key part of the v2 release. It can take some time because

  1. in full transparency, I'm recovering from what probably was covid-19, working 1/3 of my normal hours.
  2. Spark Mollie is being released the 28th of May. 🎉

That being said, rest assured you have my attention 😉 .

@jelleroorda
Copy link
Contributor Author

@sandervanhooft No worries about the timeframe, just take it easy ;).

Is the develop branch going to be the base for the V2 release branch? In that case I will just let the morphable related code be (since it won’t break any tests). Good thing to note for the upgrade guide though.

I had seen the conversation you mentioned about the “making testing easier” comment. The thing I’m envisioning is a “run this with your mollie api key, copy paste to your phpunit configuration and you’re done” kind of thing. After that you’d be able to run all the tests without figuring out what mandates or subscriptions, first payments etcetera are. Sometimes you wish to make a simple change, but you still have to run the test suite, so I thought we could make that a lot easier for simple pull requests.

Great that Spark Mollie is being released, I’m thinking of giving that a spin for a side project to play with it!

Just a thought off the top of my head; Optionally making a mandate can probably be implemented by passing [“method” => “first”] to the invoice options.

@sandervanhooft
Copy link
Collaborator

sandervanhooft commented Jul 21, 2020

Let's treat this as a breaking change, so implement it on v2-develop. (I'll set that up in a minute)

@jelleroorda jelleroorda changed the base branch from develop to v2-develop August 5, 2020 14:13
@JorisDebonnet
Copy link

If this goes into v2, I guess that means having this feature available will require waiting for any other v2 milestones to be finished as well? Or might finishing this warrant releasing v2?

@mbardelmeijer
Copy link

Any update on this feature? Would love to see this in V2 😄

@jelleroorda
Copy link
Contributor Author

Hi @mbardelmeijer, I’m not really sure about the roadmap for V2. Seeing the latest commits it looks like Sander has been improving some testing utilities lately.

@sandervanhooft
I would like to suggest to create a “V2 issue” with a roadmap of the things to do so the community also has a better idea of what’s happening, but it’s up to you of course.

@sandervanhooft
Copy link
Collaborator

I am silently (so mostly off-radar) working on v2, hope to release by the end of the year / beginning of next year. I'm tackling some fundamental changes first.

@marijnbent
Copy link
Contributor

@sandervanhooft I would love to test v2 when you have an alpha ready!

@sandervanhooft
Copy link
Collaborator

@jelleroorda We're a long way into developing the v2 alpha, almost ready for release. We have heavily based the new one-off payment features on this PR, but since there was a lot changed already we had to copy it in. Rest assured the features will be properly attributed to you on release. Big thanks and we'll get back to you soon!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

one off charge (invoiceFor)
5 participants