Create order from code (Litium 8)

Hi, I asked the same question a few months ago, and now I have to revisit the question.

The same problem still occurs.

The following error is logged from the payment app (DirectPay):

2022-08-25 10:19:18.0509 [App:01] [] [ERROR] [] Microsoft.AspNetCore.Server.Kestrel - Connection id "0HMK6ETCSDC50", Request id "0HMK6ETCSDC50:00000002": An unhandled exception was thrown by the application. System.ArgumentException: Payment(SystemId=ba42f6e4-9acf-4b61-9736-ff52953141d8) was not found. (Parameter 'paymentSystemId')
   at Litium.Connect.DirectPay.Services.PaymentService.CaptureAsync(Guid paymentSystemId, CaptureRequest capture) in /_/src/Litium.Connect.DirectPay/Services/PaymentService.cs:line 32
   at Litium.Connect.DirectPay.Controllers.PaymentsController.Capture(Guid paymentSystemId, CaptureRequest capture) in /_/src/Litium.Connect.DirectPay/Controllers/PaymentsController.cs:line 58
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   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()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

This error is pretty logical, as I just create the payment in Litium, I’m not manually sending anything to the payment app. Not really sure how to achieve this?

I’m using PaymentService to create the actual payment in Litium. Then I manually create an Init transaction and an Authorize transaction (using TransactionService), both connected to the created payment. Finally I link the payment to the order.

Litium version: 8.3.1

@NilsN

What is the use case for these orders? Are they offline orders being synced to Litium?

I’m not sure if you can ensure the payment being created in the app if you’re doing it this way.

Another way is to create the order by using a cart context. This will call the payment provider app and create the transaction.

var cartContext = await _cartContextFactory.CreateAsync(new CreateCartContextArgs
{
	ChannelSystemId = channel.SystemId,
	CountryCode = country.Id,
	CurrencyCode = currency.Id,
	MarketSystemId = channel.MarketSystemId.Value,
});

foreach (var variant in variants)
{
	await cartContext.AddOrUpdateItemAsync(new AddOrUpdateCartItemArgs
	{
		ArticleNumber = variant.Id,
		Quantity = 1,
	});
}

// must come after adding products to cart
await cartContext.TryInitializeCheckoutFlowAsync(() => new CheckoutFlowInfoArgs
{
	CheckoutFlowInfo = new CheckoutFlowInfo(),
});

await cartContext.AddOrUpdateCustomerInfoAsync(new AddOrUpdateCustomerInfoArgs
{
	CustomerInfo = new CustomerInfo
	{
		FirstName = "Test",
		LastName = "Test",
		Email = "test@example.com",
		CustomerType = CustomerType.Person,
		// PersonSystemId = ,
		// OrganizationSystemId = ,
	}
});

var address = new Address
{
	FirstName = "Test",
	LastName = "Test",
	Address1 = "Testgatan 1",
	Address2 = string.Empty,
	ZipCode = "12345",
	City = "Test",
	Country = "SE",
	Email = string.Empty,
	PhoneNumber = deliveryAddress.PhoneNumber ?? string.Empty,
	MobilePhone = deliveryAddress.PhoneNumber ?? string.Empty
};


await cartContext.AddOrUpdateDeliveryAddressAsync(address);
await cartContext.AddOrUpdateBillingAddressAsync(address);

await cartContext.SelectPaymentOptionAsync(new SelectPaymentOptionArgs
{
	PaymentOptionId = new ProviderOptionIdentifier("DirectPayment", "DirectPay"),
});

await cartContext.SelectShippingOptionAsync(new SelectShippingOptionArgs
{
	ShippingOptionId = new ProviderOptionIdentifier("DirectShipment", "standardPackage"),
});

await cartContext.ConfirmOrderAsync();
1 Like

Hi,

Yes exactly, these are orders that are coming from the customer’s ERP which they create manually.

Thanks, I will try the CartContext way!

I have some trouble when actually confirming the order, with an exception being thrown:

Object reference not set to an instance of an object.
   at Litium.Application.Sales.OrderRowExtensions.CalculateByUnitPriceIncludingVat(OrderRow orderRow, String currencyCode, RoundOffService roundOffService)
   at Litium.Accelerator.ValidationRules.ProductPricesHasNotChanged.<>c__DisplayClass7_0.<Validate>b__1(SalesOrderRow orderRow)
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source)
   at Litium.Accelerator.ValidationRules.ProductPricesHasNotChanged.Validate(ValidateCartContextArgs entity, ValidationMode validationMode)
   at Litium.Validations.ValidationRuleBase`1.ValidateAsync(T entity, ValidationMode validationMode)
   at Litium.Validations.ValidationRuleBase`1.Litium.Validations.IValidationRule.ValidateAsync(Object entity, ValidationMode validationMode)
   at Litium.Application.Validations.ValidationServiceImpl.<ValidateEntityAsync>d__7`1.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Litium.Application.Validations.ValidationServiceImpl.<ValidateAsync>d__5`1.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Litium.Application.Sales.CartContextSessionServiceImpl.<ValidateAsync>d__48.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Litium.Application.Sales.CartContextSessionServiceImpl.<ConfirmOrderAsync>d__37.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Litium.Application.Sales.CartContextImpl.<ConfirmOrderAsync>d__47.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Litium.Accelerator.Integration.Services.OrderIntegrationService.<CreateUpdateLitiumOrder>d__16.MoveNext() in C:\CustomerProject\src\Litium.Accelerator\Integration\Services\OrderIntegrationService.cs:line 215

If I just place the order using await cartContext.PlaceOrderAsync() the order is created correctly, but the payment looks invalid? If I set Confirm to true in PlaceOrderArgs, the order is still created as Init.

The problem was related to a validation that has been removed in 8.4+ Removing the "sales.validation.productprices.haschanged" validation in the checkout

1 Like

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.