Handle Spin-off events as buys (#35)
Badges / coveralls (push) Successful in 1m1s

Reviewed-on: #35
Co-authored-by: Natercio Moniz <[email protected]>
This commit was merged in pull request #35.
This commit is contained in:
natercio authored and Natercio Moniz committed 2026-10-27 22:08:18 +00:00
1 parent 41b287c804
commit 16ae9975ee
3 files changed
+288 -73

No files matched your search

+63 -4
View File
@@ -138,6 +138,69 @@ func TestRecordReader_ReadRecord(t *testing.T) {
r: bytes.NewBufferString(`Market buy,not-a-timestamp,IE000GA3D489,ABXY,"Aspargus Broccoli",EOF987654321,2.4387014200,7.3690000000,USD,1.17995999,,"EUR",15.25,"EUR",0.25,"EUR",0.02,"EUR",,`),
wantErr: true,
},
{
name: "spin off booked as zero-cost buy",
r: bytes.NewBufferString(`Spin off,2026-02-11 13:41:43+00:00,XX1234567890,ABXY,"Aspargus Broccoli",EOF987654321,0.0406450000,0E-10,USD,,,,0.00,"EUR",,,,,,`),
want: Record{
symbol: "XX1234567890",
kind: internal.KindBuy,
quantity: ShouldParseDecimal(t, "0.0406450000"),
price: decimal.Zero,
fees: decimal.Zero,
taxes: decimal.Zero,
timestamp: time.Date(2026, 2, 11, 13, 41, 43, 0, time.FixedZone("UTC", 0)),
natureGetter: func() internal.Nature { return internal.NatureG01 },
},
},
{
name: "spin off with a non-zero price is rejected",
r: bytes.NewBufferString(`Spin off,2026-02-11 13:41:43+00:00,XX1234567890,ABXY,"Aspargus Broccoli",EOF987654321,0.0406450000,45.2300000000,USD,,,,0.00,"EUR",,,,,,`),
wantErr: true,
},
{
name: "spin off with a non-zero result is rejected",
r: bytes.NewBufferString(`Spin off,2026-02-11 13:41:43+00:00,XX1234567890,ABXY,"Aspargus Broccoli",EOF987654321,0.0406450000,0E-10,USD,1.17995999,1.25,"EUR",0.00,"EUR",,,,,,`),
wantErr: true,
},
{
name: "spin off with a non-zero total is rejected",
r: bytes.NewBufferString(`Spin off,2026-02-11 13:41:43+00:00,XX1234567890,ABXY,"Aspargus Broccoli",EOF987654321,0.0406450000,0E-10,USD,,,,1.25,"EUR",,,,,,`),
wantErr: true,
},
{
name: "spin off with a non-zero stamp duty reserve tax is rejected",
r: bytes.NewBufferString(`Spin off,2026-02-11 13:41:43+00:00,XX1234567890,ABXY,"Aspargus Broccoli",EOF987654321,0.0406450000,0E-10,USD,,,,0.00,"EUR",0.25,"EUR",,,,,`),
wantErr: true,
},
{
name: "spin off with a non-zero currency conversion fee is rejected",
r: bytes.NewBufferString(`Spin off,2026-02-11 13:41:43+00:00,XX1234567890,ABXY,"Aspargus Broccoli",EOF987654321,0.0406450000,0E-10,USD,,,,0.00,"EUR",,,0.02,"EUR",,`),
wantErr: true,
},
{
name: "spin off with a non-zero french transaction tax is rejected",
r: bytes.NewBufferString(`Spin off,2026-02-11 13:41:43+00:00,XX1234567890,ABXY,"Aspargus Broccoli",EOF987654321,0.0406450000,0E-10,USD,,,,0.00,"EUR",,,,,0.1,"EUR"`),
wantErr: true,
},
{
name: "spin off with a non-positive quantity is rejected",
r: bytes.NewBufferString(`Spin off,2026-02-11 13:41:43+00:00,XX1234567890,ABXY,"Aspargus Broccoli",EOF987654321,0E-10,0E-10,USD,,,,0.00,"EUR",,,,,,`),
wantErr: true,
},
{
name: "spin off with an empty price column is booked as a zero-cost buy",
r: bytes.NewBufferString(`Spin off,2026-02-11 13:41:43+00:00,XX1234567890,ABXY,"Aspargus Broccoli",EOF987654321,0.0406450000,,USD,,,,0.00,"EUR",,,,,,`),
want: Record{
symbol: "XX1234567890",
kind: internal.KindBuy,
quantity: ShouldParseDecimal(t, "0.0406450000"),
price: decimal.Zero,
fees: decimal.Zero,
taxes: decimal.Zero,
timestamp: time.Date(2026, 2, 11, 13, 41, 43, 0, time.FixedZone("UTC", 0)),
natureGetter: func() internal.Nature { return internal.NatureG01 },
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -377,10 +440,6 @@ func TestRecordReader_ReadRecord_SkipsCorporateActions(t *testing.T) {
name string
row string
}{
{
name: "spin off",
row: `Spin off,2026-02-11 13:41:43+00:00,US9418481035,WAT,"Waters",EOF46451921527,0.0406450000,0E-10,USD,,,,0.00,"EUR",,,,,,`,
},
{
name: "stock distribution",
row: `Stock distribution,2025-08-04 11:45:30,XX1234567890,ABXY,"Aspargus Broccoli",EOF987654321,2.4387014200,7.9999999999,USD,1.17995999,,"EUR",15.25,"EUR",,,0.02,"EUR",,`,