feat(inventory): write acquire history rows on commit
CommitAsync now calls WriteAcquireHistory() between the two SaveChanges calls: iterates _ops, skips SpendOps, writes one ViewerAcquireHistoryEntry per GrantOp. Cascade rows get GrantSource.CardCosmeticCascade; wallet currencies zero RewardDetailId; all rows in a single commit share one DateTime.UtcNow timestamp. Closes _source plumbing from Task 5. 5 new tests added (46 total inventory, 0 failures). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -277,6 +277,10 @@ internal sealed class InventoryTransaction : IInventoryTransaction
|
||||
ThrowIfCommitted();
|
||||
|
||||
await _db.SaveChangesAsync(ct);
|
||||
|
||||
WriteAcquireHistory();
|
||||
await _db.SaveChangesAsync(ct);
|
||||
|
||||
await _dbTx.CommitAsync(ct);
|
||||
_committed = true;
|
||||
|
||||
@@ -285,6 +289,39 @@ internal sealed class InventoryTransaction : IInventoryTransaction
|
||||
return new InventoryCommitResult(rewardList, deltas);
|
||||
}
|
||||
|
||||
private void WriteAcquireHistory()
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var primaryMessage = GrantSourceMessages.For(_source);
|
||||
var cascadeMessage = GrantSourceMessages.For(GrantSource.CardCosmeticCascade);
|
||||
|
||||
foreach (var op in _ops)
|
||||
{
|
||||
if (op is not GrantOp grant) continue;
|
||||
|
||||
var rowSource = grant.IsCascade ? GrantSource.CardCosmeticCascade : _source;
|
||||
var rowMessage = grant.IsCascade ? cascadeMessage : primaryMessage;
|
||||
var detailId = IsWalletCurrency(grant.Type) ? 0L : grant.DetailId;
|
||||
|
||||
_db.ViewerAcquireHistory.Add(new ViewerAcquireHistoryEntry
|
||||
{
|
||||
ViewerId = Viewer.Id,
|
||||
RewardType = (int)grant.Type,
|
||||
RewardDetailId = detailId,
|
||||
RewardCount = grant.Num,
|
||||
AcquireType = (int)rowSource,
|
||||
Message = rowMessage,
|
||||
AcquireTime = now,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsWalletCurrency(UserGoodsType type) => type
|
||||
is UserGoodsType.Crystal
|
||||
or UserGoodsType.Rupy
|
||||
or UserGoodsType.RedEther
|
||||
or UserGoodsType.SpotCardPoint;
|
||||
|
||||
private IReadOnlyList<GrantedReward> BuildRewardList()
|
||||
{
|
||||
// Pass 1 — for each currency type, find the last op (spend OR grant) that touched it
|
||||
|
||||
Reference in New Issue
Block a user