This looks to be related to statistics on the InventSumDelta table which causes SQL Server to select the wrong index, i.e. the RecId index.
Here is a good article that got me on the right track to hopefully fixing this problem.
axology.wordpress.com/.../locking-on-the-inventsumdelta-table
And the follow-up.
axology.wordpress.com/.../locking-on-the-inventsumdelta-table-additional-tweaks
Here is a snip from my own SQL Server ERRORLOG from today showing the deadlock type keylock on the I_2397RECID index.
2018-07-26 09:45:54.40 spid10s (@P1 bigint)DELETE FROM INVENTSUMDELTA WHERE (((PARTITION=5637144576) AND (DATAAREAID=N'140')) AND (TTSID=@P1))
2018-07-26 09:45:54.40 spid10s resource-list
2018-07-26 09:45:54.41 spid10s keylock hobtid=72057596231221248 dbid=7 objectname=DAX2012R2_PROD.dbo.INVENTSUMDELTA indexname=I_2397RECID id=lock654fef980 mode=X associatedObjectId=72057596231221248
2018-07-26 09:45:54.41 spid10s owner-list
2018-07-26 09:45:54.41 spid10s owner id=process4fee8a7848 mode=X
2018-07-26 09:45:54.41 spid10s waiter-list
2018-07-26 09:45:54.41 spid10s waiter id=process1e1d088 mode=U requestType=wait
2018-07-26 09:45:54.41 spid10s keylock hobtid=72057596231221248 dbid=7 objectname=DAX2012R2_PROD.dbo.INVENTSUMDELTA indexname=I_2397RECID id=lock2e8dda080 mode=X associatedObjectId=72057596231221248
2018-07-26 09:45:54.41 spid10s owner-list
2018-07-26 09:45:54.41 spid10s owner id=process1e1d088 mode=X
2018-07-26 09:45:54.41 spid10s waiter-list
2018-07-26 09:45:54.41 spid10s waiter id=process4fee8a7848 mode=U requestType=wait
The more appropriate index by far for these delete_from statements it the TTSDimIdx, since the where clause specifies the PARTITION, DATAAREAID, and TTSID. It might also help to use forceliterals on those queries to eliminate a poor cached plan from causing repeated deadlocks, but I won't try that unless the specifying the index fails to resolve the issue.
The class InventUpdateOnhand contains 4 methods that delete from InventSumDelta and InventSumDeltaDim, where a forced index should resolve this issue. The cleanupAggrCounter method should probably use the AggregationIdx instead given the WHERE clause.
Just ideas.