Hi, thanks for sending me the following files:
Unfortunately I could not find the cause in these files...
Where else is an update made on the PaymentRequest?
Part 2:
2025-01-08 09:49:43.229 +00:00 [INF] PalmaStripePaymentGateway.HandleCustomerSubscriptionUpdatedAsync: Begin handle Stripe event 'customer.subscription.updated' with id 'evt_1QevtSHPiPVaq9xpIZFViU7N'. Important payload data: SubscriptionId='sub_1QevtLHPiPVaq9xpu4IS2vSf', PaymentRequestId='9e476206-1f24-2f92-334b-3a17577e5568', PlanId='price_1PuqpAHPiPVaq9xpirMIDMuj', PeriodEndDate='08.01.2026 09:49:35', ThreadId='39'
2025-01-08 09:49:43.240 +00:00 [WRN] There is an entry which is not saved due to concurrency exception:
PaymentRequest {Id: 9e476206-1f24-2f92-334b-3a17577e5568} Modified
2025-01-08 09:49:43.241 +00:00 [WRN] There is an entry which is not saved due to concurrency exception:
PaymentRequest {Id: 9e476206-1f24-2f92-334b-3a17577e5568} Modified
2025-01-08 09:49:43.251 +00:00 [INF] PalmaStripePaymentGateway.UpdatePaymentRequestWithExtraPropertiesAsync: Add extra properties to PaymentRequest '9e476206-1f24-2f92-334b-3a17577e5568': PeriodEndDateUtc='08.01.2026 09:49:35', ThreadId='38'
2025-01-08 09:49:43.261 +00:00 [INF] PalmaStripePaymentGateway.HandleCustomerSubscriptionUpdatedAsync: End handle Stripe event 'customer.subscription.updated'. Payment request updated with PeriodEndDateUtc='08.01.2026 09:49:35', ThreadId='38'
2025-01-08 09:49:43.262 +00:00 [ERR] ---------- RemoteServiceErrorInfo ----------
{
"code": null,
"message": "The data you have submitted has already changed by another user/client. Please discard the changes you've done and try from the beginning.",
"details": null,
"data": null,
"validationErrors": null
}
2025-01-08 09:49:43.287 +00:00 [ERR] ---------- RemoteServiceErrorInfo ----------
{
"code": null,
"message": "The data you have submitted has already changed by another user/client. Please discard the changes you've done and try from the beginning.",
"details": null,
"data": null,
"validationErrors": null
}
2025-01-08 09:49:43.270 +00:00 [ERR] The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See https://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
Volo.Abp.Data.AbpDbConcurrencyException: The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See https://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
---> Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See https://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyExceptionAsync(RelationalDataReader reader, Int32 commandIndex, Int32 expectedRowsAffected, Int32 rowsAffected, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeResultSetWithRowsAffectedOnlyAsync(Int32 commandIndex, RelationalDataReader reader, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Update.Internal.SqlServerModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Volo.Abp.EntityFrameworkCore.AbpDbContext`1.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at Volo.Abp.EntityFrameworkCore.AbpDbContext`1.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Volo.Abp.Uow.UnitOfWork.SaveChangesAsync(CancellationToken cancellationToken)
at Volo.Abp.AspNetCore.Mvc.Uow.AbpUowActionFilter.SaveChangesAsync(ActionExecutingContext context, IUnitOfWorkManager unitOfWorkManager)
at Volo.Abp.AspNetCore.Mvc.Uow.AbpUowActionFilter.SaveChangesAsync(ActionExecutingContext context, IUnitOfWorkManager unitOfWorkManager)
at Volo.Abp.AspNetCore.Mvc.Uow.AbpUowActionFilter.OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
2025-01-08 09:49:43.291 +00:00 [ERR] The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See https://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
Volo.Abp.Data.AbpDbConcurrencyException: The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See https://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
---> Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See https://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyExceptionAsync(RelationalDataReader reader, Int32 commandIndex, Int32 expectedRowsAffected, Int32 rowsAffected, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeResultSetWithRowsAffectedOnlyAsync(Int32 commandIndex, RelationalDataReader reader, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Update.Internal.SqlServerModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Volo.Abp.EntityFrameworkCore.AbpDbContext`1.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at Volo.Abp.EntityFrameworkCore.AbpDbContext`1.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Volo.Abp.Uow.UnitOfWork.SaveChangesAsync(CancellationToken cancellationToken)
at Volo.Abp.AspNetCore.Mvc.Uow.AbpUowActionFilter.SaveChangesAsync(ActionExecutingContext context, IUnitOfWorkManager unitOfWorkManager)
at Volo.Abp.AspNetCore.Mvc.Uow.AbpUowActionFilter.SaveChangesAsync(ActionExecutingContext context, IUnitOfWorkManager unitOfWorkManager)
at Volo.Abp.AspNetCore.Mvc.Uow.AbpUowActionFilter.OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
2025-01-08 09:49:44.065 +00:00 [INF] PalmaPaymentRequestAppService.CompleteAsync, paymentGateway='stripe', ThreadId='35'
2025-01-08 09:49:44.263 +00:00 [INF] PalmaStripePaymentGateway.CompleteAsync: Begin complete Stripe request. PaymentRequest='9e476206-1f24-2f92-334b-3a17577e5568'
2025-01-08 09:49:44.271 +00:00 [INF] PalmaStripePaymentGateway.CompleteAsync: End complete Stripe request. PaymentRequest='9e476206-1f24-2f92-334b-3a17577e5568' updated with currency & state, ThreadId='35'
Here is an excerpt from the log file, I have tried to make as many log messages as possible. But unfortunately I can't see where exactly the exceptions are happening, as this seems to come from your module.
Due to the character limitation in two parts...
Part 1:
2025-01-08 09:49:16.002 +00:00 [INF] PalmaPaymentRequestAppService.CreateAsync, ThreadId='38'
2025-01-08 09:49:16.103 +00:00 [INF] PalmaPaymentRequestAppService.UpdateWithExtraPropertiesAsync: PaymentRequest '9e476206-1f24-2f92-334b-3a17577e5568' updated with extra properties: TenantId='70938969-ef4a-ba91-a4ca-3a16f1add23d', TerminationId='01dfb6ef-fb21-6f9d-8b85-3a16f1af3030', ThreadId='21'
2025-01-08 09:49:16.614 +00:00 [INF] PalmaPaymentRequestAppService.StartAsync, ThreadId='21'
2025-01-08 09:49:17.940 +00:00 [INF] PalmaStripePaymentGateway.StartAsync: Start Stripe request. PaymentRequest='9e476206-1f24-2f92-334b-3a17577e5568'
2025-01-08 09:49:42.494 +00:00 [INF] PalmaPaymentRequestAppService.HandleWebhookAsync, paymentGateway='stripe', eventType='customer.subscription.created', ThreadId='39'
2025-01-08 09:49:42.505 +00:00 [INF] PalmaStripePaymentGateway.HandleWebhookAsync: Receive Stripe event 'customer.subscription.created' with id 'evt_1QevtRHPiPVaq9xpEy1e75VL'
2025-01-08 09:49:42.511 +00:00 [INF] PalmaStripePaymentGateway.HandleCustomerSubscriptionCreatedAsync: Begin handle Stripe event 'customer.subscription.created' with id 'evt_1QevtRHPiPVaq9xpEy1e75VL'. Important payload data: SubscriptionId='sub_1QevtLHPiPVaq9xpu4IS2vSf', PaymentRequestId='9e476206-1f24-2f92-334b-3a17577e5568', ThreadId='39'
2025-01-08 09:49:42.653 +00:00 [INF] PalmaPaymentRequestAppService.HandleWebhookAsync, paymentGateway='stripe', eventType='invoice.finalized', ThreadId='39'
2025-01-08 09:49:42.755 +00:00 [INF] PalmaStripePaymentGateway.HandleWebhookAsync: Receive Stripe event 'invoice.finalized' with id 'evt_1QevtRHPiPVaq9xpOSrJK4Kk'
2025-01-08 09:49:42.777 +00:00 [INF] PalmaPaymentRequestAppService.HandleWebhookAsync, paymentGateway='stripe', eventType='checkout.session.completed', ThreadId='38'
2025-01-08 09:49:42.787 +00:00 [INF] PalmaStripePaymentGateway.HandleCustomerSubscriptionCreatedAsync: End handle Stripe event 'customer.subscription.created'. Payment request updated with ExternalSubscriptionId='sub_1QevtLHPiPVaq9xpu4IS2vSf', ThreadId='39'
2025-01-08 09:49:42.804 +00:00 [INF] PalmaStripePaymentGateway.HandleWebhookAsync: Receive Stripe event 'checkout.session.completed' with id 'evt_1QevtRHPiPVaq9xp7aJCb7vy'
2025-01-08 09:49:42.819 +00:00 [WRN] PalmaStripePaymentGateway.HandleCheckoutSessionCompletedAsync: Unhandled Stripe event 'checkout.session.completed' with id 'evt_1QevtRHPiPVaq9xp7aJCb7vy'
2025-01-08 09:49:42.814 +00:00 [INF] PalmaStripePaymentGateway.HandleInvoiceAsync: Begin handle Stripe event 'invoice.finalized' with id 'evt_1QevtRHPiPVaq9xpOSrJK4Kk'. Important payload data: SubscriptionId='sub_1QevtLHPiPVaq9xpu4IS2vSf', PaymentRequestId='9e476206-1f24-2f92-334b-3a17577e5568', InvoiceId='in_1QevtL***', CustomerName='Buyer Paypal', CustomerEmail='buyer.paypal@***', AmountDue='12000', AmountPaid='0', AmountRemaining=='12000', InvoiceUrl='https://invoice.stripe.com/i/a***', ThreadId='39'
2025-01-08 09:49:42.883 +00:00 [INF] PalmaStripePaymentGateway.UpdatePaymentRequestWithExtraPropertiesAsync: Add extra properties to PaymentRequest '9e476206-1f24-2f92-334b-3a17577e5568': ExternalCustomerName='Buyer Paypal', ExternalCustomerEmailAddress='buyer.paypal@***', AmountDue='12000', AmountPaid='0', AmountRemaining='12000', InvoiceUrl='https://invoice.stripe.com/i/a***', ThreadId='39'
2025-01-08 09:49:42.894 +00:00 [INF] PalmaStripePaymentGateway.HandleInvoiceAsync: End handle Stripe event 'invoice.finalized'. Payment request updated with invoice data, ThreadId='39'
2025-01-08 09:49:42.922 +00:00 [INF] PalmaPaymentRequestAppService.HandleWebhookAsync, paymentGateway='stripe', eventType='invoice.payment_succeeded', ThreadId='38'
2025-01-08 09:49:42.963 +00:00 [INF] PalmaStripePaymentGateway.HandleWebhookAsync: Receive Stripe event 'invoice.payment_succeeded' with id 'evt_1QevtSHPiPVaq9xpu6c9BDJ2'
2025-01-08 09:49:42.974 +00:00 [INF] PalmaStripePaymentGateway.HandleInvoiceAsync: Begin handle Stripe event 'invoice.payment_succeeded' with id 'evt_1QevtSHPiPVaq9xpu6c9BDJ2'. Important payload data: SubscriptionId='sub_1QevtLHPiPVaq9xpu4IS2vSf', PaymentRequestId='9e476206-1f24-2f92-334b-3a17577e5568', InvoiceId='in_1QevtLHPiPVaq9xpj9VPg1w0', CustomerName='Buyer Paypal', CustomerEmail='buyer.paypal@***', AmountDue='12000', AmountPaid='12000', AmountRemaining=='0', InvoiceUrl='https://invoice.stripe.com/i/a***', ThreadId='38'
2025-01-08 09:49:43.023 +00:00 [INF] PalmaPaymentRequestAppService.HandleWebhookAsync, paymentGateway='stripe', eventType='customer.subscription.updated', ThreadId='39'
2025-01-08 09:49:43.027 +00:00 [INF] PalmaStripePaymentGateway.HandleWebhookAsync: Receive Stripe event 'customer.subscription.updated' with id 'evt_1QevtSHPiPVaq9xpIZFViU7N'
2025-01-08 09:49:43.219 +00:00 [INF] PalmaStripePaymentGateway.UpdatePaymentRequestWithExtraPropertiesAsync: Add extra properties to PaymentRequest '9e476206-1f24-2f92-334b-3a17577e5568': ExternalCustomerName='Buyer Paypal', ExternalCustomerEmailAddress='buyer.paypal@***', AmountDue='12000', AmountPaid='12000', AmountRemaining='0', InvoiceUrl='https://invoice.stripe.com/i/a***', ThreadId='39'
2025-01-08 09:49:43.221 +00:00 [INF] PalmaStripePaymentGateway.HandleInvoiceAsync: End handle Stripe event 'invoice.payment_succeeded'. Payment request updated with invoice data, ThreadId='39'
You can publish an event in
PalmaTenantDatabaseMigrationHandler
Ah yes, that's it. Thank you!
Ok, I've seen the problem. It's because my TenantEventHandler was called first and then PalmaTenantDatabaseMigrationHandler, which creates the admin user.
Probably you can't specify a order?
I would simply prefer to have my logic in a separate EventHandler, as there are also further steps (sending mail etc.) which have nothing to do with database migration...
public async Task HandleEventAsync(TenantCreatedEto eventData)
{
await MigrateAndSeedForTenantAsync(
eventData.Id,
eventData.Properties.GetOrDefault("AdminEmail") ?? PalmaConsts.AdminEmailDefaultValue,
eventData.Properties.GetOrDefault("AdminPassword") ?? PalmaConsts.AdminPasswordDefaultValue
);
using (_currentTenant.Change(eventData.Id))
{
// Set admin user as confirmed
var adminUser = await _userManager.FindByEmailAsync(PalmaConsts.AdminEmailDefaultValue);
if (adminUser != null)
{
adminUser.SetEmailConfirmed(true);
await _userManager.UpdateAsync(adminUser);
}
}
}
Another problem: After creating the tenant (TenantAppService.CreateAsync), I would like to change something about the user. But it seems that the user is not yet in the database. It is not (yet) found...
Is the transaction only completed after all EventHandlers have been handled? Or is this a timing problem?
public class TenantEventHandler : IDistributedEventHandler<TenantCreatedEto>, ITransientDependency
{
private readonly IdentityUserManager _userManager;
private readonly ICurrentTenant _currentTenant;
public TenantEventHandler(IdentityUserManager userManager, ICurrentTenant currentTenant)
{
_userManager = userManager;
_currentTenant = currentTenant;
}
public async Task HandleEventAsync(TenantCreatedEto eventData)
{
using (_currentTenant.Change(eventData.Id))
{
// Set admin user as confirmed
var adminUser = await _userManager.FindByEmailAsync(PalmaConsts.AdminEmailDefaultValue);
if (adminUser != null)
{
adminUser.SetEmailConfirmed(true);
await _userManager.UpdateAsync(adminUser);
}
}
}
[AllowAnonymous] works, thank you for the hint.
I am using version 8.2.2... maybe it's already fixed in 8.3?
maybe you can try
It's not that important to me, I just wanted to make a contribution to improving ABP.
My next problem: The tenant should be created automatically when a customer registers. Now, of course, I have a problem with the permissions, as certain rights are required to create a tenant and an anonymous user cannot have these.
I have already extended the TenantAppService and the CreateAsync method, but the permissions are taken from the base class.
How can I achieve my goal?
You don't need to extend TenantAppService, you can use data seeder.: https://abp.io/docs/latest/framework/infrastructure/data-seeding
Thank you, that worked.
Not yet definitely. We have to wait for a few decisions from the customer and I would therefore like to leave the question open so that we can ask again later if necessary.