Change price to 0 with calculations causes tax divide by 0 crash

While testing my new discount system I think ive found a bug.
I calculate my discounts in this rule, its not my rounding of calculations in this rule.

I know its not these as adding a 0 priced order doesnt crash it i just dont get a calculation (that was before adding the attempt to prevent crach with the addition of the > and <= parts of the constraints to prevent the /0.05 being the issue.

image

The issue comes where if I start a ticket and add orders valid for discount which is applied then change the order to 0.
Have tried adding a calculation update execute command directly after the update price action to no avail.
It seems to crash even before the price is changes and anything recalculated;

-----------------------------
[General Info]

Application: SambaPOS
Version:     5.1.58
Region:      en
DB:          SQ
Machine:     EPOS-SERVER
User:        EPOS
Date:        2018-03-12
Time:        04:40

User Explanation:

EPOS said ""
-----------------------------

[Exception Info 1]

Top-level Exception
Type:        System.Reflection.TargetInvocationException
Message:     Exception has been thrown by the target of an invocation.
Source:      mscorlib
Stack Trace: at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Delegate.DynamicInvokeImpl(Object[] args)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()
   at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Windows.Threading.DispatcherOperation.Invoke()
   at System.Windows.Threading.Dispatcher.ProcessQueue()
   at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at System.Windows.Threading.DispatcherOperation.Wait(TimeSpan timeout)
   at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherOperation operation, CancellationToken cancellationToken, TimeSpan timeout)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at Samba.Presentation.Services.Common.ExtensionMethods.PublishEvent[TEventSubject](TEventSubject eventArgs, String eventTopic, Boolean wait)
   at Samba.Presentation.Services.Implementations.AutomationModule.NotificationClient.<>c.<NotifyEvent>b__3_0(ActionData x)
   at Samba.Services.Implementations.AutomationModule.ActionDataBuilder.InvokeFor(Action`1 dataAction)
   at CallSite.Target(Closure , CallSite , Object , Action`1 )
   at Samba.Services.Implementations.AutomationModule.RuleExecutor.ExecuteWithoutLogging(Object dataParameter, Action`1 dataAction)
   at Samba.Services.Implementations.AutomationModule.RuleExecutor.ExecuteWith(Object dataParameter, Action`1 dataAction)
   at Samba.Services.Implementations.AutomationModule.NotificationService.NotifyEvent(String eventName, Object dataParameter, Int32 terminalId, Int32 departmentId, Int32 userRoleId, Int32 ticketTypeId, Action`1 dataAction)
   at Samba.Presentation.Services.Implementations.AutomationModule.NotificationClient.NotifyEvent(String eventName, Object dataObject)
   at CallSite.Target(Closure , CallSite , INotificationClient , String , Object )
   at Samba.Modules.PosModule.TicketViewModel.ExecuteAutomationCommand(String automationCommandName, String automationCommandValue, String nextCommandValue, Object dataObject, Boolean executeOnce, Boolean clearSelection)
   at Samba.Modules.PosModule.TicketViewModel.ExecuteAutomationCommand(AutomationCommand automationCommand, Object dataObject, String selectedValue, String nextValue)
   at Samba.Modules.PosModule.TicketViewModel.OnExecuteAutomationCommand(CommandContainerButton obj)
   at Microsoft.Practices.Prism.Commands.DelegateCommand`1.<>c__DisplayClass6.<.ctor>b__2(Object o)
   at Microsoft.Practices.Prism.Commands.DelegateCommandBase.Execute(Object parameter)
   at Microsoft.Practices.Prism.Commands.DelegateCommandBase.System.Windows.Input.ICommand.Execute(Object parameter)
   at MS.Internal.Commands.CommandHelpers.CriticalExecuteCommandSource(ICommandSource commandSource, Boolean userInitiated)
   at System.Windows.Controls.Primitives.ButtonBase.OnClick()
   at System.Windows.Controls.Primitives.ToggleButton.OnClick()
   at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
   at System.Windows.UIElement.OnMouseLeftButtonUpThunk(Object sender, MouseButtonEventArgs e)
   at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
   at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
   at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
   at System.Windows.Input.InputManager.ProcessStagingArea()
   at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
   at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
   at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
   at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at System.Windows.Application.RunDispatcher(Object ignore)
   at System.Windows.Application.RunInternal(Window window)
   at System.Windows.Application.Run(Window window)
   at Samba.Presentation.App.Main()

Inner Exception 1
Type:        System.Reflection.TargetInvocationException
Message:     Exception has been thrown by the target of an invocation.
Source:      mscorlib
Stack Trace: at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Delegate.DynamicInvokeImpl(Object[] args)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()
   at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Windows.Threading.DispatcherOperation.Invoke()
   at System.Windows.Threading.Dispatcher.ProcessQueue()
   at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at System.Windows.Threading.DispatcherOperation.Wait(TimeSpan timeout)
   at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherOperation operation, CancellationToken cancellationToken, TimeSpan timeout)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at Samba.Presentation.Services.Common.ExtensionMethods.PublishEvent[TEventSubject](TEventSubject eventArgs, String eventTopic, Boolean wait)
   at Samba.Modules.TicketModule.ActionProcessors.ExecuteTicketCommand.Process(ActionData actionData)
   at Samba.Services.Common.RuleActionTypeRegistry.ProcessAction(String actionType, ActionData actionData)
   at Samba.Services.Implementations.AutomationModule.AutomationService.ProcessAction(String actionType, ActionData actionData)
   at Samba.Modules.AutomationModule.AutomationModule.<OnInitialization>b__5_0(EventParameters`1 x)
   at Microsoft.Practices.Prism.Events.EventSubscription`1.InvokeAction(Action`1 action, TPayload argument)
   at Microsoft.Practices.Prism.Events.EventSubscription`1.<>c__DisplayClass2.<GetExecutionStrategy>b__0(Object[] arguments)
   at Microsoft.Practices.Prism.Events.EventBase.InternalPublish(Object[] arguments)
   at Microsoft.Practices.Prism.Events.CompositePresentationEvent`1.Publish(TPayload payload)
   at Samba.Presentation.Services.Common.ExtensionMethods.Publish[TEventsubject](TEventsubject eventArgs, String eventTopic, Action expectedAction)

Inner Exception 2
Type:        System.DivideByZeroException
Message:     Attempted to divide by zero.
Source:      mscorlib
Stack Trace: at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)
   at Samba.Domain.Models.Tickets.TaxValue.GetTaxAmount(Boolean taxIncluded, Decimal price, Decimal totalRate, Decimal plainSum, Decimal preTaxServices)
   at Samba.Domain.Models.Tickets.Order.<>c__DisplayClass191_0.<GetTotalTaxAmount>b__0(TaxValue x)
   at System.Linq.Enumerable.WhereSelectListIterator`2.MoveNext()
   at System.Linq.Enumerable.Sum(IEnumerable`1 source)
   at Samba.Domain.Models.Tickets.Order.GetTotalTaxAmount(Boolean taxIncluded, Decimal plainSum, Decimal preTaxServices)
   at Samba.Domain.Models.Tickets.Ticket.GetTaxExcludedSum(Order order)
   at Samba.Domain.Models.Tickets.Ticket.<Recalculate>b__206_2(Order x)
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Enumerable.Sum(IEnumerable`1 source)
   at Samba.Domain.Models.Tickets.Ticket.Recalculate()
   at Samba.Presentation.Services.Implementations.TicketModule.TicketService.RecalculateTicket(Ticket ticket, Boolean forceRecalculation)
   at Samba.Modules.PosModule.TicketOrdersViewModel.CancelSelectedOrders()
   at Samba.Modules.PosModule.TicketViewModel.CancelItem()
   at Samba.Modules.PosModule.TicketViewModel.OnTicketEvent(EventParameters`1 obj)
   at Microsoft.Practices.Prism.Events.EventSubscription`1.InvokeAction(Action`1 action, TPayload argument)
   at Microsoft.Practices.Prism.Events.EventSubscription`1.<>c__DisplayClass2.<GetExecutionStrategy>b__0(Object[] arguments)
   at Microsoft.Practices.Prism.Events.EventBase.InternalPublish(Object[] arguments)
   at Microsoft.Practices.Prism.Events.CompositePresentationEvent`1.Publish(TPayload payload)
   at Samba.Presentation.Services.Common.ExtensionMethods.Publish[TEventsubject](TEventsubject eventArgs, String eventTopic, Action expectedAction)

-----------------------------

[Assembly Info]

mscorlib, Version=4.0.0.0
DevExpress.Xpf.LayoutControl.v14.1, Version=14.1.11.0
System.Xml, Version=4.0.0.0
DevExpress.Xpf.Grid.v14.1, Version=14.1.11.0
System, Version=4.0.0.0
DevExpress.Xpf.Grid.v14.1.Core, Version=14.1.11.0
WindowsBase, Version=4.0.0.0
System.Xaml, Version=4.0.0.0
Samba.Domain, Version=1.0.0.0
System.Core, Version=4.0.0.0
PresentationFramework, Version=4.0.0.0
Samba.Infrastructure, Version=1.0.0.0
Microsoft.Practices.Prism, Version=4.0.0.0
System.Runtime.Serialization, Version=4.0.0.0
Microsoft.Practices.Prism.MefExtensions, Version=4.0.0.0
System.ComponentModel.Composition, Version=4.0.0.0
PresentationCore, Version=4.0.0.0
DevExpress.Xpf.Core.v14.1, Version=14.1.11.0
Samba.Services, Version=1.0.0.0
Samba.Presentation.Services, Version=1.0.0.0
System.Windows.Forms, Version=4.0.0.0
System.Drawing, Version=4.0.0.0
Stateless, Version=1.0.0.0
Samba.Persistance, Version=1.0.0.0
PropertyTools, Version=2012.4.14.1
Samba.Localization, Version=1.0.0.0
ReachFramework, Version=4.0.0.0
Samba.Infrastructure.Data, Version=1.0.0.0
EntityFramework, Version=6.0.0.0
FluentValidation, Version=3.4.0.0
Omu.ValueInjecter, Version=2.3.0.0
Microsoft.Practices.ServiceLocation, Version=1.0.0.0
Microsoft.CSharp, Version=4.0.0.0

-----------------------------

[System Info]

Operating System
-Microsoft Windows 10 Pro
--CodeSet = 1252
--CSDVersion = 
--CurrentTimeZone = 0
--FreePhysicalMemory = 8561668
--OSArchitecture = 64-bit
--OSLanguage = 1033
--ServicePackMajorVersion = 0
--ServicePackMinorVersion = 0
--Version = 10.0.16299

Machine
-EPOS-SERVER
--Manufacturer = Dell Inc.
--Model = OptiPlex 990
--TotalPhysicalMemory = 12760047616
--UserName = EPOS-SERVER\EPOS

-----------------------------

So it looks like your using ask question to change price… what your not showing is that automation. I am guessing but are you initiating the ask question on Order Added rule? It could be that your changing price to 0 before it calculates tax… if you do that it will try to divide by 0 which is not allowed obviously.

I dont think it is a bug that error is very specific. I think you need to slowly remove some of the automation until you find the culprit. Likely its an order of what your doing things.

But you can’t move tax processing automation in sort order.

Here is my change price rule. I have tried moving it infront of the update discount rule to check if that would help but does not.

Apreciate your comments kendash.

Furtheur tinkering and its nothing to do with the automation of changing price.

If I do the following it still happens;

Add 1 order
Add another order
Change price of seccond order to 0
Cancel first order
CRASH

Looks like it’s trying to still calculate something. Notice the balance even though ticket is zero.

The error specifily mentions tax…

So unmap taxes see if it does it.

Ok, will try tomorrow.

Unmapped tax and doesnt happen anymore…
What do you suggest?

I suggest figuring out why tax is not recalculating when you change price to 0. Under most circumstances it does so something is blocking that. I am thinking its the way you are changing price… there is a hardcoded element to it that I think taxes are tied too.

Im pretty confident the issue is the combination of discounts and tax.
It only does it with discounts applied and tax active.
Think maybe whatever catches issue normally hasnt been applied when discount part calculated.
If I I set the calculation type to ‘include tax’ which actually would make more sence as exclude tax as its still calculated on the total before discount it doesnt happen.
I would say @emre could you look at this but probably not going to help.

How are you doing discounts?

Calculation though math and update calculation.
If I set calculation to ‘include tax’ (aka exclude tax) it doesnt crash.
Unmap tax no crash.
Tax mapped and no calculation no crash.
Pretty confident its the tax part of the calculation causing the crash.

Origionally though it might be the math for working out the calculation
[=Math.floor((TN('{TICKET ORDER TOTAL EXP:(OS.NewBook GLA=2101)&&(ODI=True)&&(OS.GStatus= )}')*0.1)/0.05)*0.05]

Since there was a divide in here and it would be dividing 0 product price however changing to this;
[=Math.floor(((TN('{TICKET ORDER TOTAL EXP:(OS.NewBook GLA=2101)&&(ODI=True)&&(OS.GStatus= )}')+0.01)*0.1)/0.05)*0.05]
To prevent a 0 order total still crashes.

So are you actually using that expression in a Calculation Type?? I am confused what you mean by Calculation through math?

Im using update calculation action with a [=calculation] to work out the value.
I said maths rather than say using calculation to update calculation lol

So you probably need to clear the calculation before you change price to 0. Since your using automation for it, it is probably trying to calculate on 0 which causes the crash.

But no tax stops crash.
And adding 0.01 in the calculation to prevent 0/0.05 (the rounding maths)
Pretty sure its not the calculation update thats causing the divide by 0 issue but the tax coding doesnt have a exemption when discounts are involved.
I cant forse calculation to update before tax as tax automation is hardcoded.
If I add expressions to only update if orders have a value and clear calculation if not (using actions in place for if discount type is removed/changed it doesnt help;

Can you please post a “pseudo” calculation that you believe is being performed when the divide by zero “with Tax and Discount [calculation]” error occurs?

Walk us through it step-by-step using small formulas with known values instead of all the Report/Expression junk in there.

For example, if I were to Calculate Tax on something:

taxAmount = price * (tax / 100)
totalPrice = price + taxAmount

… or shorter:

totalPrice = price + ( price * (tax / 100) )

Given:

price = 10
tax = 25

… then:

totalPrice = 10 + ( 10 * (25 / 100) )
totalPrice = 10 + ( 2.5 )
so...
totalPrice == 12.5

I see no opportunity for “divide by zero”…

Given:

price = 0
tax = 25

… then:

totalPrice = 0 + ( 0 * (25 / 100) )
totalPrice = 0 + ( 0 )
so...
totalPrice == 0

… that’s what I would expect.

How does the Discount calculation come into play that might cause this?

I’m not sure…
0 total with tax setup is fine
Non 0 total with discount applied and tax setup is fine
0 total with discount setup but no tax mapped is fine
But 0 total with discounts and tax setup causes crash…
If iscount is set to not include tax it’s ok

I think it’s calculating tax on plain total and the tax on the discount and that’s causing issue somewhere in the flow.
Kendash said to push the removal of the discount when it changes to 0 to top/first but since we can’t choose where tax is calculated in automation order I think it’s updating the tax before automation has had chance to run.

I can’t say for sure but there is an issue somewhere.

Either that for it doesn’t like calculating tax on a 0 total (0 divided by rather than divided by 0 perhaps but maybe there is a exception/catch code which prevents the crash.

I’m sure I remember an issue with crashing related to 0 total or tax before and it got fixed.