Subscription cancellation fee

Help for integrating the Laravel package
Forum rules
Always add your Laravel, Aimeos and PHP version as well as your environment (Linux/Mac/Win)
Spam and unrelated posts will be removed immediately!
mrkepzie
Posts: 5
Joined: 03 Jun 2024, 06:37

Subscription cancellation fee

Post by mrkepzie » 03 Jun 2024, 06:42

HI,

We are currently assessing whether aimeos would be a good fit to port some of our custom store logic.
One feature we offer to our clients is annual subscription with monthly payments (using Stripe). This is equivalent to a monthly subscription, except that when the customer cancels, we charge a cancellation fee of 50% of the remaining balance.
Is there anyway to do this in aimeos ? For what we gathered by looking at the code, the Stripe integration is just a backend wiring of payment logic within aimeos itself (i.e: they are not Stripe subscriptions, aimeos manages the renewal).
I'm guessing adding cancellation fees would require some code modifications, could you point us in the right place where we could implement such logic ?

Thank you

Version: 2024.04 on laravel + php 8.3

User avatar
aimeos
Administrator
Posts: 8616
Joined: 01 Jan 1970, 00:00

Re: Subscription cancellation fee

Post by aimeos » 04 Jun 2024, 07:09

The best place is to create a new subscription processor and implement the code for the cancellation fee in the end() method: https://aimeos.org/docs/latest/cronjobs ... rocessors/
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

mrkepzie
Posts: 5
Joined: 03 Jun 2024, 06:37

Re: Subscription cancellation fee

Post by mrkepzie » 06 Jun 2024, 06:47

Thank you for your pointer. We've been trying making a new processor in a new package (and registered it in the config/controller.php), which for now just logs begin/renewAfter/end events.
A few questions:

- It seems a begin/end can be called multiple times with the same customerID/orderID. We have setup a PT1H (1h) subscription for testing and set the cron jobs of aimeos:jobs subscription/process/{begin,renew,end} to every minute. Is this supposed to be called multiple times? Actually I have a reproducer:
In the backoffice -> Sales -> Subscription, I just set the End date to a day before, set reason to canceled and press save. This triggers a new processor/end event every times I press Send, even though it was already ended.

- Can subscription end dates be specified with a specific time also in the backoffice ? When testing with a 1h subscription it's not really clear when it is going to be ended

- On subscription renew, we have the following messages in the aimeos log:

Code: Select all

Unable to renew subscription with ID "12": SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '27-payment' for key 'mshop_order_address.unq_msordad_pid_type': 
Also we get sometimes the following error on subscription/renew, even though the product is configured with unlimited stocks:

Code: Select all

Unable to renew subscription with ID "4": Products out of stock
- This one is more of a aimeos backoffice usage: we used the Cgroup processor as example and associated active subscriptions to the group "activeSubscription". However there doesn't seem to be a way to inspect membership of a user to a group, nor it is possible to list users in a group, am I mistaken? How do you manage user groups then?
Last edited by mrkepzie on 06 Jun 2024, 07:22, edited 2 times in total.

User avatar
aimeos
Administrator
Posts: 8616
Joined: 01 Jan 1970, 00:00

Re: Subscription cancellation fee

Post by aimeos » 07 Jun 2024, 09:54

mrkepzie wrote: 06 Jun 2024, 06:47 - It seems a begin/end can be called multiple times with the same customerID/orderID. We have setup a PT1H (1h) subscription for testing and set the cron jobs of aimeos:jobs subscription/process/{begin,renew,end} to every minute. Is this supposed to be called multiple times? Actually I have a reproducer:
In the backoffice -> Sales -> Subscription, I just set the End date to a day before, set reason to canceled and press save. This triggers a new processor/end event every times I press Send, even though it was already ended.
Ending subscriptions is independent of how often you set the end date in the admin backend to the same value in the past because the job controller isn't executed directly by the subscription panel in the admin backend but only by the cronjob you've set up:

According to the subscription end job controller, only active subscriptions (status > 0) with and end date in the past will be selected and processed:
https://github.com/aimeos/ai-controller ... d.php#L166

Afterwards, each subscription item is set to status = 0 so it won't be processed again:
https://github.com/aimeos/ai-controller ... d.php#L293

We can only think of one reason why the subscription didn't end successfully and is processed again and again. If you have an error in your subscription processor and an exception is thrown which prevents the new item status from being set. Check in the Log panel for possible errors caught here:
https://github.com/aimeos/ai-controller ... d.php#L186
mrkepzie wrote: 06 Jun 2024, 06:47 - Can subscription end dates be specified with a specific time also in the backoffice ? When testing with a 1h subscription it's not really clear when it is going to be ended
Unfortunately this is missing up to now. In dev-master, you can now specify a time too.
mrkepzie wrote: 06 Jun 2024, 06:47 - On subscription renew, we have the following messages in the aimeos log:

Code: Select all

Unable to renew subscription with ID "12": SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '27-payment' for key 'mshop_order_address.unq_msordad_pid_type': 
Also we get sometimes the following error on subscription/renew, even though the product is configured with unlimited stocks:

Code: Select all

Unable to renew subscription with ID "4": Products out of stock
Can you investigate a bit more why the order address is added twice and the product is out of stock?
Stocks are checked here for example:
https://github.com/aimeos/aimeos-core/b ... tStock.php
mrkepzie wrote: 06 Jun 2024, 06:47 - This one is more of a aimeos backoffice usage: we used the Cgroup processor as example and associated active subscriptions to the group "activeSubscription". However there doesn't seem to be a way to inspect membership of a user to a group, nor it is possible to list users in a group, am I mistaken? How do you manage user groups then?
User groups can be viewed and managed in Users > Customers detail panel.
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

mrkepzie
Posts: 5
Joined: 03 Jun 2024, 06:37

Re: Subscription cancellation fee

Post by mrkepzie » 07 Jun 2024, 17:00

Ok so this is my guess, after going through the debugger: Since the renew job only checks the date and not the time (i.e: 'Y-m-d '), it will always pick up a PT1H subscription since the subscription.datenext is the same as the current date.
This means that if the cron job (or if manually executing artisan aimeos:jobs subscription/process/renew), it will actually trigger the payment in process(), but fail to save the order afterwards.
So with the current release, hourly subscriptions are buggy (but it's "ok" since we don't really care about them, it's more for debugging and checking.). I'm guessing this is already fixed in dev-master as the format is changed to ''Y-m-d H:i:s'

EDIT: Actually the exception is still around and occurs everytimes on renew:

Code: Select all

Exception has occurred.
Aimeos\Base\DB\Exception: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '737-payment' for key 'mshop_order_address.unq_msordad_pid_type': 
					INSERT INTO "mshop_order_address" ( 
						"parentid", "addrid", "type", "company", "vatid", "salutation",
						"title", "firstname", "lastname", "address1", "address2",
						"address3", "postal", "city", "state", "countryid", "langid",
						"telephone", "mobile", "email", "telefax", "website", "longitude", "latitude",
						"pos", "birthday", "mtime", "editor", "siteid", "ctime"
					) VALUES ( 
						?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?
					)
				["737","","payment","","","","","","","","","","","","",null,null,"","","email@example.com","","",0,0,0,null,"2024-06-07 18:15:38","aimeos:jobs","1.","2024-06-07 18:15:38"]

EDIT2: After further digging, there seems to be an issue in the renewal process.
When calling process() for subscription/process/renew, this creates a new order and calls addBasketAddresses(). This function resets the orderAddress ID to NULL
https://github.com/aimeos/ai-controller ... d.php#L214
It then goes on and and save the newly create order. When returning to the run() function, it attemps to save() the subscription (and thus orderAddress), but it's ID is NULL (which is fine, because it should be generated by the DB), except that the newly created order was previously recorded with the same parentID (basket ID), and so the exception is thrown...
This looks like a bug to me and can't see how it would work otherwise.

========
Unfortunately this is missing up to now. In dev-master, you can now specify a time too.
Would it be safe to update to dev-master to get that feature ?

Code: Select all

 User groups can be viewed and managed in Users > Customers detail panel.
All I see in the details view for each user is a list of all existing groups:
Screenshot 2024-06-07 at 18.58.50.png
Screenshot 2024-06-07 at 18.58.50.png (22.5 KiB) Viewed 92823 times
In this case I did not add this user to any of these groups
Last edited by mrkepzie on 08 Jun 2024, 08:00, edited 2 times in total.

User avatar
aimeos
Administrator
Posts: 8616
Joined: 01 Jan 1970, 00:00

Re: Subscription cancellation fee

Post by aimeos » 08 Jun 2024, 10:16

mrkepzie wrote: 07 Jun 2024, 17:00

Code: Select all

 User groups can be viewed and managed in Users > Customers detail panel.
All I see in the details view for each user is a list of all existing groups:
In this case I did not add this user to any of these groups
None of the groups is selected, so no one is assigned to the user. Managing groups is only allowed by admins and super users.
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

User avatar
aimeos
Administrator
Posts: 8616
Joined: 01 Jan 1970, 00:00

Re: Subscription cancellation fee

Post by aimeos » 08 Jun 2024, 10:19

mrkepzie wrote: 07 Jun 2024, 17:00
Unfortunately this is missing up to now. In dev-master, you can now specify a time too.
Would it be safe to update to dev-master to get that feature ?
There won't be much changes in the next four weeks until 2024.07 is released so it should be relatively save.
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

mrkepzie
Posts: 5
Joined: 03 Jun 2024, 06:37

Re: Subscription cancellation fee

Post by mrkepzie » 08 Jun 2024, 11:02

Thank you

Circling back on the exception:
The cause is the save of the orderItem on the renew job, since the order.id is the same as the order that was given in the begin job. Getting this know pretty much always on renew:

Code: Select all

PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1207-payment' for key 'mshop_order_address.unq_msordad_pid_type'

User avatar
aimeos
Administrator
Posts: 8616
Joined: 01 Jan 1970, 00:00

Re: Subscription cancellation fee

Post by aimeos » 10 Jun 2024, 08:08

Can you please be a bit more specific where the error occurs here?
https://github.com/aimeos/ai-controller ... andard.php

Also, does it always occur or only if you add your own subscription processor?
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

mrkepzie
Posts: 5
Joined: 03 Jun 2024, 06:37

Re: Subscription cancellation fee

Post by mrkepzie » 10 Jun 2024, 10:21

The error occurs even without any additional code:

- I order a subscription of a product with PT1H
- The subscription/process/begin job is executed and properly saves the order
- Upon executing the subscription/process/renew job the following occurs: The process() function creates a new order copied from the original order (saved in begin job) and save it https://github.com/aimeos/ai-controller ... d.php#L557 (The creation of the new order, copies addresses and set the original order addresses ID to NULL: https://github.com/aimeos/ai-controller ... d.php#L214). Then when it returns from process(), it calls save() on the original orderItem (the one with the ID that was generated from the begin job) https://github.com/aimeos/ai-controller ... d.php#L182 When saving the orderItem, it calls saveAddresses() in https://github.com/aimeos/aimeos-core/b ... e.php#L200 which fails with the exception mentionned, probably because the ID of the address was set to NULL by the addBaskedAddresses() function

Post Reply