Skip to content

Commit d400ae5

Browse files
Merge pull request #816 from TransactionProcessing/task/#798_add_deposits_and_withdrwals_to_statements
Add deposits and withdrawals to Merchant Statement system
2 parents b38b507 + 8984752 commit d400ae5

File tree

18 files changed

+829
-582
lines changed

18 files changed

+829
-582
lines changed

TransactionProcessor.Aggregates.Tests/MerchantStatementAggregateTests.cs

Lines changed: 0 additions & 306 deletions
Large diffs are not rendered by default.
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
using Shouldly;
2+
using TransactionProcessor.Models.Merchant;
3+
using TransactionProcessor.Testing;
4+
5+
namespace TransactionProcessor.Aggregates.Tests;
6+
7+
public class MerchantStatementForDateAggregateTests
8+
{
9+
[Fact]
10+
public void MerchantStatementForDateAggregate_CanBeCreated_IsCreated()
11+
{
12+
MerchantStatementForDateAggregate merchantStatementForDateAggregate = MerchantStatementForDateAggregate.Create(TestData.MerchantStatementForDateId1);
13+
14+
merchantStatementForDateAggregate.ShouldNotBeNull();
15+
merchantStatementForDateAggregate.AggregateId.ShouldBe(TestData.MerchantStatementForDateId1);
16+
}
17+
18+
[Fact]
19+
public void MerchantStatementForDateAggregate_AddTransactionToStatement_TransactionAddedToStatement()
20+
{
21+
MerchantStatementForDateAggregate merchantStatementForDateAggregate = MerchantStatementForDateAggregate.Create(TestData.MerchantStatementForDateId1);
22+
merchantStatementForDateAggregate.AddTransactionToStatement(TestData.MerchantStatementId,
23+
TestData.StatementDate,
24+
TestData.EventId1,
25+
TestData.EstateId,
26+
TestData.MerchantId, TestData.Transaction1);
27+
28+
MerchantStatementForDate merchantStatementForDate = merchantStatementForDateAggregate.GetStatement(true);
29+
List<MerchantStatementLine>? statementLines = merchantStatementForDate.GetStatementLines();
30+
statementLines.ShouldNotBeNull();
31+
statementLines.ShouldNotBeEmpty();
32+
statementLines.Count.ShouldBe(1);
33+
}
34+
35+
[Fact]
36+
public void MerchantStatementForDateAggregate_AddTransactionToStatement_DuplicateTransaction_SilentlyHandled()
37+
{
38+
MerchantStatementForDateAggregate merchantStatementForDateAggregate = MerchantStatementForDateAggregate.Create(TestData.MerchantStatementForDateId1);
39+
merchantStatementForDateAggregate.AddTransactionToStatement(TestData.MerchantStatementId,
40+
TestData.StatementDate,
41+
TestData.EventId1,
42+
TestData.EstateId,
43+
TestData.MerchantId, TestData.Transaction1);
44+
45+
merchantStatementForDateAggregate.AddTransactionToStatement(TestData.MerchantStatementId,
46+
TestData.StatementDate,
47+
TestData.EventId1,
48+
TestData.EstateId,
49+
TestData.MerchantId, TestData.Transaction1);
50+
51+
MerchantStatementForDate merchantStatementForDate = merchantStatementForDateAggregate.GetStatement(true);
52+
List<MerchantStatementLine>? statementLines = merchantStatementForDate.GetStatementLines();
53+
statementLines.ShouldNotBeNull();
54+
statementLines.ShouldNotBeEmpty();
55+
statementLines.Count.ShouldBe(1);
56+
}
57+
58+
[Fact]
59+
public void MerchantStatementForDateAggregate_AddSettledFeeToStatement_FeeAddedToStatement()
60+
{
61+
MerchantStatementForDateAggregate merchantStatementForDateAggregate = MerchantStatementForDateAggregate.Create(TestData.MerchantStatementForDateId1);
62+
merchantStatementForDateAggregate.AddSettledFeeToStatement(TestData.MerchantStatementId, TestData.StatementDate, TestData.EventId1, TestData.EstateId, TestData.MerchantId, TestData.SettledFee1);
63+
64+
MerchantStatementForDate merchantStatementForDate = merchantStatementForDateAggregate.GetStatement(true);
65+
List<MerchantStatementLine>? statementLines = merchantStatementForDate.GetStatementLines();
66+
statementLines.ShouldNotBeNull();
67+
statementLines.ShouldNotBeEmpty();
68+
statementLines.Count.ShouldBe(1);
69+
}
70+
71+
[Fact]
72+
public void MerchantStatementForDateAggregate_AddSettledFeeToStatement_DuplicateFee_Silentlyhandled()
73+
{
74+
MerchantStatementForDateAggregate merchantStatementForDateAggregate = MerchantStatementForDateAggregate.Create(TestData.MerchantStatementForDateId1);
75+
merchantStatementForDateAggregate.AddSettledFeeToStatement(TestData.MerchantStatementId, TestData.StatementDate, TestData.EventId1, TestData.EstateId, TestData.MerchantId, TestData.SettledFee1);
76+
merchantStatementForDateAggregate.AddSettledFeeToStatement(TestData.MerchantStatementId, TestData.StatementDate, TestData.EventId1, TestData.EstateId, TestData.MerchantId, TestData.SettledFee1);
77+
78+
MerchantStatementForDate merchantStatementForDate = merchantStatementForDateAggregate.GetStatement(true);
79+
List<MerchantStatementLine>? statementLines = merchantStatementForDate.GetStatementLines();
80+
statementLines.ShouldNotBeNull();
81+
statementLines.ShouldNotBeEmpty();
82+
statementLines.Count.ShouldBe(1);
83+
}
84+
85+
[Theory]
86+
[InlineData(MerchantDepositSource.Manual)]
87+
[InlineData(MerchantDepositSource.Automatic)]
88+
public void MerchantStatementForDateAggregate_AddDepositToStatement_DepositAddedToStatement(MerchantDepositSource source)
89+
{
90+
MerchantStatementForDateAggregate merchantStatementForDateAggregate = MerchantStatementForDateAggregate.Create(TestData.MerchantStatementForDateId1);
91+
merchantStatementForDateAggregate.AddDepositToStatement(TestData.MerchantStatementId,
92+
TestData.StatementDate,
93+
TestData.EventId1,
94+
TestData.EstateId,
95+
TestData.MerchantId, new Deposit {
96+
DepositDateTime = TestData.DepositDateTime,
97+
Amount = TestData.DepositAmount.Value,
98+
DepositId = TestData.DepositId,
99+
Reference = TestData.DepositReference,
100+
Source = source
101+
});
102+
103+
MerchantStatementForDate merchantStatementForDate = merchantStatementForDateAggregate.GetStatement(true);
104+
List<MerchantStatementLine>? statementLines = merchantStatementForDate.GetStatementLines();
105+
statementLines.ShouldNotBeNull();
106+
statementLines.ShouldNotBeEmpty();
107+
statementLines.Count.ShouldBe(1);
108+
}
109+
110+
[Fact]
111+
public void MerchantStatementForDateAggregate_AddWithdrawalToStatement_WithdrawalAddedToStatement()
112+
{
113+
MerchantStatementForDateAggregate merchantStatementForDateAggregate = MerchantStatementForDateAggregate.Create(TestData.MerchantStatementForDateId1);
114+
merchantStatementForDateAggregate.AddWithdrawalToStatement(TestData.MerchantStatementId,
115+
TestData.StatementDate,
116+
TestData.EventId1,
117+
TestData.EstateId,
118+
TestData.MerchantId, new Withdrawal
119+
{
120+
WithdrawalDateTime = TestData.WithdrawalDateTime,
121+
Amount = TestData.WithdrawalAmount.Value,
122+
WithdrawalId = TestData.WithdrawalId
123+
});
124+
125+
MerchantStatementForDate merchantStatementForDate = merchantStatementForDateAggregate.GetStatement(true);
126+
List<MerchantStatementLine>? statementLines = merchantStatementForDate.GetStatementLines();
127+
statementLines.ShouldNotBeNull();
128+
statementLines.ShouldNotBeEmpty();
129+
statementLines.Count.ShouldBe(1);
130+
}
131+
132+
133+
[Fact]
134+
public void MerchantStatementAggregate_AddDailySummaryRecord_RecordIsAdded() {
135+
MerchantStatementAggregate merchantStatementAggregate = MerchantStatementAggregate.Create(TestData.MerchantStatementId);
136+
Should.NotThrow(() => { merchantStatementAggregate.AddDailySummaryRecord(TestData.TransactionDateTime.Date, 1, 100.00m, 1, 0.10m,
137+
1, 1000, 1, 200); });
138+
}
139+
140+
[Fact]
141+
public void MerchantStatementAggregate_AddDailySummaryRecord_DuplicateAdd_ExceptionIsThrown()
142+
{
143+
MerchantStatementAggregate merchantStatementAggregate = MerchantStatementAggregate.Create(TestData.MerchantStatementId);
144+
merchantStatementAggregate.AddDailySummaryRecord(TestData.TransactionDateTime.Date, 1, 100.00m, 1, 0.10m,
145+
1, 1000, 1, 200);
146+
Should.Throw<InvalidOperationException>(() => { merchantStatementAggregate.AddDailySummaryRecord(TestData.TransactionDateTime.Date, 1, 100.00m, 1, 0.10m,
147+
1, 1000, 1, 200); });
148+
}
149+
150+
151+
[Fact]
152+
public void MerchantStatementAggregate_GenerateStatement_StatementIsGenerated()
153+
{
154+
MerchantStatementAggregate merchantStatementAggregate = MerchantStatementAggregate.Create(TestData.MerchantStatementId);
155+
merchantStatementAggregate.AddDailySummaryRecord(TestData.TransactionDateTime.Date, 1, 100.00m, 1, 0.10m,
156+
1, 1000, 1, 200);
157+
merchantStatementAggregate.GenerateStatement(TestData.StatementGeneratedDate);
158+
159+
MerchantStatement merchantStatement = merchantStatementAggregate.GetStatement();
160+
merchantStatement.IsGenerated.ShouldBeTrue();
161+
}
162+
163+
[Fact]
164+
public void MerchantStatementAggregate_GenerateStatement_StatementIsAlreadyGenerated_ExceptionThrown()
165+
{
166+
MerchantStatementAggregate merchantStatementAggregate = MerchantStatementAggregate.Create(TestData.MerchantStatementId);
167+
merchantStatementAggregate.AddDailySummaryRecord(TestData.TransactionDateTime.Date, 1, 100.00m, 1, 0.10m, 1, 1000, 1, 200);
168+
merchantStatementAggregate.GenerateStatement(TestData.StatementGeneratedDate);
169+
Should.Throw<InvalidOperationException>(() => {
170+
merchantStatementAggregate.GenerateStatement(TestData.StatementGeneratedDate);
171+
});
172+
}
173+
174+
[Fact]
175+
public void MerchantStatementAggregate_GenerateStatement_NoSummaries_ExceptionThrown()
176+
{
177+
MerchantStatementAggregate merchantStatementAggregate = MerchantStatementAggregate.Create(TestData.MerchantStatementId);
178+
179+
Should.Throw<InvalidOperationException>(() => {
180+
merchantStatementAggregate.GenerateStatement(TestData.StatementGeneratedDate);
181+
});
182+
}
183+
184+
[Fact]
185+
public void MerchantStatementAggregate_BuildStatement_StatementIsBuilt()
186+
{
187+
MerchantStatementAggregate merchantStatementAggregate = MerchantStatementAggregate.Create(TestData.MerchantStatementId);
188+
merchantStatementAggregate.AddDailySummaryRecord(TestData.TransactionDateTime.Date, 1, 100.00m, 1, 0.10m, 1, 1000, 1, 200);
189+
merchantStatementAggregate.GenerateStatement(TestData.StatementGeneratedDate);
190+
merchantStatementAggregate.BuildStatement(TestData.StatementBuiltDate,TestData.StatementData);
191+
192+
MerchantStatement merchantStatement = merchantStatementAggregate.GetStatement();
193+
merchantStatement.BuiltDateTime.ShouldBe(TestData.StatementBuiltDate);
194+
}
195+
196+
[Fact]
197+
public void MerchantStatementAggregate_BuildStatement_StatementIsAlreadyBuilt_ExceptionThrown()
198+
{
199+
MerchantStatementAggregate merchantStatementAggregate = MerchantStatementAggregate.Create(TestData.MerchantStatementId);
200+
merchantStatementAggregate.AddDailySummaryRecord(TestData.TransactionDateTime.Date, 1, 100.00m, 1, 0.10m, 1, 1000, 1, 200);
201+
merchantStatementAggregate.GenerateStatement(TestData.StatementGeneratedDate);
202+
merchantStatementAggregate.BuildStatement(TestData.StatementBuiltDate, TestData.StatementData);
203+
204+
Should.Throw<InvalidOperationException>(() => {
205+
merchantStatementAggregate.BuildStatement(TestData.StatementBuiltDate, TestData.StatementData);
206+
});
207+
}
208+
209+
[Fact]
210+
public void MerchantStatementAggregate_BuildStatement_StatementIsNotGenerated_ExceptionThrown()
211+
{
212+
MerchantStatementAggregate merchantStatementAggregate = MerchantStatementAggregate.Create(TestData.MerchantStatementId);
213+
merchantStatementAggregate.AddDailySummaryRecord(TestData.TransactionDateTime.Date, 1, 100.00m, 1, 0.10m, 1, 1000, 1, 200);
214+
215+
Should.Throw<InvalidOperationException>(() => {
216+
merchantStatementAggregate.BuildStatement(TestData.StatementBuiltDate, TestData.StatementData);
217+
});
218+
}
219+
220+
[Fact]
221+
public void MerchantStatementAggregate_EmailStatement_StatementIsEmailed()
222+
{
223+
MerchantStatementAggregate merchantStatementAggregate = MerchantStatementAggregate.Create(TestData.MerchantStatementId);
224+
merchantStatementAggregate.AddDailySummaryRecord(TestData.TransactionDateTime.Date, 1, 100.00m, 1, 0.10m, 1, 1000, 1, 200);
225+
merchantStatementAggregate.GenerateStatement(TestData.StatementGeneratedDate);
226+
merchantStatementAggregate.BuildStatement(TestData.StatementBuiltDate, TestData.StatementData);
227+
228+
merchantStatementAggregate.EmailStatement(TestData.StatementEmailedDate, TestData.MessageId);
229+
230+
MerchantStatement merchantStatement = merchantStatementAggregate.GetStatement();
231+
merchantStatement.HasBeenEmailed.ShouldBeTrue();
232+
}
233+
234+
[Fact]
235+
public void MerchantStatementAggregate_EmailStatement_StatementIsAlreadyEmailed_ExceptionThrown()
236+
{
237+
MerchantStatementAggregate merchantStatementAggregate = MerchantStatementAggregate.Create(TestData.MerchantStatementId);
238+
merchantStatementAggregate.AddDailySummaryRecord(TestData.TransactionDateTime.Date, 1, 100.00m, 1, 0.10m, 1, 1000, 1, 200);
239+
merchantStatementAggregate.GenerateStatement(TestData.StatementGeneratedDate);
240+
merchantStatementAggregate.BuildStatement(TestData.StatementBuiltDate, TestData.StatementData);
241+
merchantStatementAggregate.EmailStatement(TestData.StatementEmailedDate, TestData.MessageId);
242+
243+
Should.Throw<InvalidOperationException>(() => {
244+
merchantStatementAggregate.EmailStatement(TestData.StatementEmailedDate, TestData.MessageId);
245+
});
246+
}
247+
248+
[Fact]
249+
public void MerchantStatementAggregate_EmailStatement_StatementIsNotBuilt_ExceptionThrown()
250+
{
251+
MerchantStatementAggregate merchantStatementAggregate = MerchantStatementAggregate.Create(TestData.MerchantStatementId);
252+
merchantStatementAggregate.AddDailySummaryRecord(TestData.TransactionDateTime.Date, 1, 100.00m, 1, 0.10m, 1, 1000, 1, 200);
253+
merchantStatementAggregate.GenerateStatement(TestData.StatementGeneratedDate);
254+
255+
Should.Throw<InvalidOperationException>(() => {
256+
merchantStatementAggregate.EmailStatement(TestData.StatementEmailedDate, TestData.MessageId);
257+
});
258+
}
259+
}

TransactionProcessor.Aggregates/MerchantStatementAggregate.cs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -213,14 +213,6 @@ public static void GenerateStatement(this MerchantStatementAggregate aggregate,
213213
aggregate.ApplyAndAppend(statementGeneratedEvent);
214214
}
215215

216-
private static void EnsureStatementHasBeenCreated(this MerchantStatementAggregate aggregate)
217-
{
218-
if (aggregate.IsCreated == false)
219-
{
220-
throw new InvalidOperationException("Statement header has not been created");
221-
}
222-
}
223-
224216
private static void EnsureStatementHasBeenGenerated(this MerchantStatementAggregate aggregate)
225217
{
226218
if (aggregate.IsGenerated == false)
@@ -261,15 +253,19 @@ private static void EnsureStatementHasNotAlreadyBeenEmailed(this MerchantStateme
261253
}
262254
}
263255

264-
public static void AddDailySummaryRecord(this MerchantStatementAggregate aggregate, DateTime activityDate, Int32 numberOfTransactions, Decimal valueOfTransactions, Int32 numberOfSettledFees, Decimal valueOfSettledFees) {
256+
public static void AddDailySummaryRecord(this MerchantStatementAggregate aggregate, DateTime activityDate,
257+
Int32 numberOfTransactions, Decimal valueOfTransactions,
258+
Int32 numberOfSettledFees, Decimal valueOfSettledFees,
259+
Int32 numberOfDepoits, Decimal valueOfDepoits,
260+
Int32 numberOfWithdrawals, Decimal valueOfWithdrawals) {
265261
if (aggregate.MerchantStatementSummaries.Any(s => s.ActivityDate == activityDate)) {
266262
throw new InvalidOperationException($"Summary Data for Activity Date {activityDate:yyyy-MM-dd} already exists");
267263
}
268264

269265
// TODO: should this check the date has been added to the statement, before allowing the summary?
270266

271267
MerchantStatementDomainEvents.StatementSummaryForDateEvent statementSummaryForDateEvent = new(aggregate.AggregateId, aggregate.EstateId, aggregate.MerchantId, activityDate,aggregate.MerchantStatementSummaries.Count +1
272-
,numberOfTransactions, valueOfTransactions, numberOfSettledFees, valueOfSettledFees);
268+
,numberOfTransactions, valueOfTransactions, numberOfSettledFees, valueOfSettledFees, numberOfDepoits, valueOfDepoits, numberOfWithdrawals, valueOfWithdrawals);
273269
aggregate.ApplyAndAppend(statementSummaryForDateEvent);
274270
}
275271
}

0 commit comments

Comments
 (0)