From fb257a544f1930da1f01208cb00353155a4783ca Mon Sep 17 00:00:00 2001 From: gamer147 Date: Fri, 29 May 2026 14:17:01 -0400 Subject: [PATCH] refactor(leaderskin): route currency spend through CurrencySpendService Co-Authored-By: Claude Sonnet 4.6 --- .../Controllers/LeaderSkinController.cs | 78 ++++++++++--------- 1 file changed, 43 insertions(+), 35 deletions(-) diff --git a/SVSim.EmulatedEntrypoint/Controllers/LeaderSkinController.cs b/SVSim.EmulatedEntrypoint/Controllers/LeaderSkinController.cs index a85850a..2c1baa9 100644 --- a/SVSim.EmulatedEntrypoint/Controllers/LeaderSkinController.cs +++ b/SVSim.EmulatedEntrypoint/Controllers/LeaderSkinController.cs @@ -30,12 +30,14 @@ public class LeaderSkinController : SVSimController private readonly SVSimDbContext _db; private readonly RewardGrantService _rewards; private readonly TimeProvider _time; + private readonly ICurrencySpendService _spend; - public LeaderSkinController(SVSimDbContext db, RewardGrantService rewards, TimeProvider time) + public LeaderSkinController(SVSimDbContext db, RewardGrantService rewards, TimeProvider time, ICurrencySpendService spend) { _db = db; _rewards = rewards; _time = time; + _spend = spend; } [HttpPost("set")] @@ -175,7 +177,7 @@ public class LeaderSkinController : SVSimController return BadRequest(new { error = "already_purchased" }); var rewardList = new List(); - var debit = DebitProductPrice(viewer, product, request.SalesType); + var debit = await DebitProductPrice(viewer, product, request.SalesType); if (debit.Error is not null) return BadRequest(new { error = debit.Error }); if (debit.PostState is not null) rewardList.Add(debit.PostState); @@ -206,7 +208,7 @@ public class LeaderSkinController : SVSimController var viewer = await LoadViewerGraphAsync(viewerId); var rewardList = new List(); - var debit = DebitSetPrice(viewer, series, request.SalesType); + var debit = await DebitSetPrice(viewer, series, request.SalesType); if (debit.Error is not null) return BadRequest(new { error = debit.Error }); if (debit.PostState is not null) rewardList.Add(debit.PostState); @@ -332,52 +334,58 @@ public class LeaderSkinController : SVSimController return false; } - private (RewardListEntry? PostState, string? Error) DebitProductPrice( + private async Task<(RewardListEntry? PostState, string? Error)> DebitProductPrice( Viewer viewer, LeaderSkinShopProductEntry product, int salesType) { - return salesType switch + switch (salesType) { - 0 when product.SinglePriceCrystal == 0 && product.SinglePriceRupy == 0 => (null, null), - 0 => (null, "price_not_available_for_currency"), - 1 => product.SinglePriceCrystal is null - ? (null, "price_not_available_for_currency") - : DebitCrystal(viewer, product.SinglePriceCrystal.Value), - 2 => product.SinglePriceRupy is null - ? (null, "price_not_available_for_currency") - : DebitRupy(viewer, product.SinglePriceRupy.Value), - _ => (null, "invalid_sales_type"), - }; + case 0 when product.SinglePriceCrystal == 0 && product.SinglePriceRupy == 0: + return (null, null); + case 0: + return (null, "price_not_available_for_currency"); + case 1: + if (product.SinglePriceCrystal is null) return (null, "price_not_available_for_currency"); + return await DebitCrystal(viewer, product.SinglePriceCrystal.Value); + case 2: + if (product.SinglePriceRupy is null) return (null, "price_not_available_for_currency"); + return await DebitRupy(viewer, product.SinglePriceRupy.Value); + default: + return (null, "invalid_sales_type"); + } } - private (RewardListEntry? PostState, string? Error) DebitSetPrice( + private async Task<(RewardListEntry? PostState, string? Error)> DebitSetPrice( Viewer viewer, LeaderSkinShopSeriesEntry series, int salesType) { - return salesType switch + switch (salesType) { - 0 when series.SetPriceCrystal == 0 && series.SetPriceRupy == 0 => (null, null), - 0 => (null, "price_not_available_for_currency"), - 1 => series.SetPriceCrystal is null - ? (null, "price_not_available_for_currency") - : DebitCrystal(viewer, series.SetPriceCrystal.Value), - 2 => series.SetPriceRupy is null - ? (null, "price_not_available_for_currency") - : DebitRupy(viewer, series.SetPriceRupy.Value), - _ => (null, "invalid_sales_type"), - }; + case 0 when series.SetPriceCrystal == 0 && series.SetPriceRupy == 0: + return (null, null); + case 0: + return (null, "price_not_available_for_currency"); + case 1: + if (series.SetPriceCrystal is null) return (null, "price_not_available_for_currency"); + return await DebitCrystal(viewer, series.SetPriceCrystal.Value); + case 2: + if (series.SetPriceRupy is null) return (null, "price_not_available_for_currency"); + return await DebitRupy(viewer, series.SetPriceRupy.Value); + default: + return (null, "invalid_sales_type"); + } } - private static (RewardListEntry?, string?) DebitCrystal(Viewer viewer, int amount) + private async Task<(RewardListEntry?, string?)> DebitCrystal(Viewer viewer, int amount) { - if (viewer.Currency.Crystals < (ulong)amount) return (null, "insufficient_crystals"); - viewer.Currency.Crystals -= (ulong)amount; - return (new RewardListEntry { RewardType = 2, RewardId = 0, RewardNum = (int)viewer.Currency.Crystals }, null); + var r = await _spend.TrySpendAsync(viewer, SpendCurrency.Crystal, amount); + if (!r.Success) return (null, "insufficient_crystals"); + return (new RewardListEntry { RewardType = 2, RewardId = 0, RewardNum = (int)r.PostStateTotal }, null); } - private static (RewardListEntry?, string?) DebitRupy(Viewer viewer, int amount) + private async Task<(RewardListEntry?, string?)> DebitRupy(Viewer viewer, int amount) { - if (viewer.Currency.Rupees < (ulong)amount) return (null, "insufficient_rupees"); - viewer.Currency.Rupees -= (ulong)amount; - return (new RewardListEntry { RewardType = 9, RewardId = 0, RewardNum = (int)viewer.Currency.Rupees }, null); + var r = await _spend.TrySpendAsync(viewer, SpendCurrency.Rupee, amount); + if (!r.Success) return (null, "insufficient_rupees"); + return (new RewardListEntry { RewardType = 9, RewardId = 0, RewardNum = (int)r.PostStateTotal }, null); } private async Task ApplyRewardsAsync(