Billing: Update EBICS exporter
This commit is contained in:
@ -1,32 +0,0 @@
|
|||||||
using Elwig.Models.Entities;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Elwig.Helpers.Billing {
|
|
||||||
public class Transaction {
|
|
||||||
|
|
||||||
public readonly Member Member;
|
|
||||||
public readonly long AmountCent;
|
|
||||||
public readonly string Currency;
|
|
||||||
public readonly int Nr;
|
|
||||||
|
|
||||||
public Transaction(Member m, decimal amount, string currency, int nr) {
|
|
||||||
Member = m;
|
|
||||||
AmountCent = (long)Math.Round(amount * 100);
|
|
||||||
Currency = currency;
|
|
||||||
Nr = nr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<Transaction> FromPaymentVariant(PaymentVar variant) {
|
|
||||||
var last = variant.Season.PaymentVariants.Where(v => v.TransferDate != null).OrderBy(v => v.TransferDate).LastOrDefault();
|
|
||||||
var dict = last?.MemberPayments.ToDictionary(m => m.MgNr, m => m.Amount) ?? new();
|
|
||||||
return variant.Credits
|
|
||||||
.OrderBy(c => c.MgNr)
|
|
||||||
.Select(c => new Transaction(c.Member, c.Amount, variant.Season.CurrencyCode, c.TgNr))
|
|
||||||
.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string FormatAmountCent(long cents) => $"{cents / 100}.{cents % 100:00}";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
using Elwig.Helpers.Billing;
|
using Elwig.Models.Dtos;
|
||||||
using Elwig.Models.Entities;
|
using Elwig.Models.Entities;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -7,32 +7,24 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Elwig.Helpers.Export {
|
namespace Elwig.Helpers.Export {
|
||||||
public class Ebics : IBankingExporter {
|
public class Ebics(PaymentVar variant, string filename) : IBankingExporter {
|
||||||
|
|
||||||
public static string FileExtension => "xml";
|
public static string FileExtension => "xml";
|
||||||
|
|
||||||
private readonly StreamWriter _writer;
|
private readonly StreamWriter Writer = new(filename, false, Utils.UTF8);
|
||||||
private readonly DateOnly _date;
|
private readonly DateOnly Date = variant.TransferDate ?? throw new ArgumentException("TransferDate has to be set in PaymentVar");
|
||||||
private readonly int _year;
|
private readonly int Year = variant.Year;
|
||||||
private readonly string _name;
|
private readonly string Name = variant.Name;
|
||||||
private readonly int _nr;
|
private readonly int AvNr = variant.AvNr;
|
||||||
|
|
||||||
public Ebics(PaymentVar variant, string filename) {
|
|
||||||
_writer = new(filename, false, Utils.UTF8);
|
|
||||||
_date = variant.TransferDate ?? DateOnly.Parse("2021-01-10"); //throw new ArgumentException("TransferDate has to be set in PaymentVar");
|
|
||||||
_year = variant.Year;
|
|
||||||
_name = variant.Name;
|
|
||||||
_nr = variant.AvNr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose() {
|
public void Dispose() {
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
_writer.Dispose();
|
Writer.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask DisposeAsync() {
|
public ValueTask DisposeAsync() {
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
return _writer.DisposeAsync();
|
return Writer.DisposeAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Export(IEnumerable<Transaction> transactions, IProgress<double>? progress = null) {
|
public void Export(IEnumerable<Transaction> transactions, IProgress<double>? progress = null) {
|
||||||
@ -43,66 +35,66 @@ namespace Elwig.Helpers.Export {
|
|||||||
progress?.Report(0.0);
|
progress?.Report(0.0);
|
||||||
var nbOfTxs = transactions.Count();
|
var nbOfTxs = transactions.Count();
|
||||||
int count = nbOfTxs + 2, i = 0;
|
int count = nbOfTxs + 2, i = 0;
|
||||||
var ctrlSum = Transaction.FormatAmountCent(transactions.Sum(tx => tx.AmountCent));
|
var ctrlSum = transactions.Sum(tx => tx.Amount);
|
||||||
var msgId = $"ELWIG-{App.Client.NameToken}-{_year}-AV{_nr:00}";
|
var msgId = $"ELWIG-{App.Client.NameToken}-{Year}-AV{AvNr:00}";
|
||||||
var pmtInfId = $"{msgId}-1";
|
var pmtInfId = $"{msgId}-1";
|
||||||
|
|
||||||
await _writer.WriteLineAsync($"""
|
await Writer.WriteLineAsync($"""
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.09"
|
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.09"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:pain.001.001.09 pain.001.001.09.xsd">
|
xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:pain.001.001.09 pain.001.001.09.xsd">
|
||||||
<CstmrCdtTrfInitn>
|
<CstmrCdtTrfInitn>
|
||||||
<GrpHdr>
|
<GrpHdr>
|
||||||
<MsgId>{msgId}</MsgId>
|
<MsgId>{msgId}</MsgId>
|
||||||
<CreDtTm>{DateTime.UtcNow:o}</CreDtTm>
|
<CreDtTm>{DateTime.UtcNow:o}</CreDtTm>
|
||||||
<NbOfTxs>{nbOfTxs}</NbOfTxs>
|
<NbOfTxs>{nbOfTxs}</NbOfTxs>
|
||||||
<CtrlSum>{ctrlSum}</CtrlSum>
|
<CtrlSum>{Transaction.FormatAmount(ctrlSum)}</CtrlSum>
|
||||||
<InitgPty><Nm>{App.Client.NameFull}</Nm></InitgPty>
|
<InitgPty><Nm>{App.Client.NameFull}</Nm></InitgPty>
|
||||||
</GrpHdr>
|
</GrpHdr>
|
||||||
<PmtInf>
|
<PmtInf>
|
||||||
<PmtInfId>{pmtInfId}</PmtInfId>
|
<PmtInfId>{pmtInfId}</PmtInfId>
|
||||||
<PmtMtd>TRF</PmtMtd>
|
<PmtMtd>TRF</PmtMtd>
|
||||||
<NbOfTxs>{nbOfTxs}</NbOfTxs>
|
<NbOfTxs>{nbOfTxs}</NbOfTxs>
|
||||||
<CtrlSum>{ctrlSum}</CtrlSum>
|
<CtrlSum>{Transaction.FormatAmount(ctrlSum)}</CtrlSum>
|
||||||
<ReqdExctnDt><Dt>{_date:yyyy-MM-dd}</Dt></ReqdExctnDt>
|
<ReqdExctnDt><Dt>{Date:yyyy-MM-dd}</Dt></ReqdExctnDt>
|
||||||
<Dbtr><Nm>{App.Client.NameFull}</Nm></Dbtr>
|
<Dbtr><Nm>{App.Client.NameFull}</Nm></Dbtr>
|
||||||
<DbtrAcct><Id><IBAN>{App.Client.Iban?.Replace(" ", "")}</IBAN></Id></DbtrAcct>
|
<DbtrAcct><Id><IBAN>{App.Client.Iban?.Replace(" ", "")}</IBAN></Id></DbtrAcct>
|
||||||
<DbtrAgt><FinInstnId><BICFI>{App.Client.Bic ?? "NOTPROVIDED"}</BICFI></FinInstnId></DbtrAgt>
|
<DbtrAgt><FinInstnId><BICFI>{App.Client.Bic ?? "NOTPROVIDED"}</BICFI></FinInstnId></DbtrAgt>
|
||||||
""");
|
""");
|
||||||
progress?.Report(100.0 * ++i / count);
|
progress?.Report(100.0 * ++i / count);
|
||||||
|
|
||||||
foreach (var tx in transactions) {
|
foreach (var tx in transactions) {
|
||||||
var a = (IAddress?)tx.Member.BillingAddress ?? tx.Member;
|
var a = (IAddress?)tx.Member.BillingAddress ?? tx.Member;
|
||||||
var (a1, a2) = Utils.SplitAddress(a.Address);
|
var (a1, a2) = Utils.SplitAddress(a.Address);
|
||||||
var id = $"ELWIG-{App.Client.NameToken}-{_year}-TG{tx.Nr:0000}";
|
var id = $"ELWIG-{App.Client.NameToken}-{Year}-TG{tx.Nr:0000}";
|
||||||
var info = $"{_name} - Traubengutschrift {_year}/{tx.Nr:000}";
|
var info = $"{Name} - Traubengutschrift Nr. {Year}/{tx.Nr:000}";
|
||||||
await _writer.WriteLineAsync($"""
|
await Writer.WriteLineAsync($"""
|
||||||
<CdtTrfTxInf>
|
<CdtTrfTxInf>
|
||||||
<PmtId><EndToEndId>{id}</EndToEndId></PmtId>
|
<PmtId><EndToEndId>{id}</EndToEndId></PmtId>
|
||||||
<Amt><InstdAmt Ccy="{tx.Currency}">{Transaction.FormatAmountCent(tx.AmountCent)}</InstdAmt></Amt>
|
<Amt><InstdAmt Ccy="{tx.Currency}">{Transaction.FormatAmount(tx.Amount)}</InstdAmt></Amt>
|
||||||
<Cdtr>
|
<Cdtr>
|
||||||
<Nm>{a.Name}</Nm>
|
<Nm>{a.Name}</Nm>
|
||||||
<PstlAdr>
|
<PstlAdr>
|
||||||
<StrtNm>{a1}</StrtNm><BldgNb>{a2}</BldgNb>
|
<StrtNm>{a1}</StrtNm><BldgNb>{a2}</BldgNb>
|
||||||
<PstCd>{a.PostalDest.AtPlz?.Plz}</PstCd><TwnNm>{a.PostalDest.AtPlz?.Ort.Name}</TwnNm>
|
<PstCd>{a.PostalDest.AtPlz?.Plz}</PstCd><TwnNm>{a.PostalDest.AtPlz?.Ort.Name}</TwnNm>
|
||||||
<Ctry>{a.PostalDest.Country.Alpha2}</Ctry>
|
<Ctry>{a.PostalDest.Country.Alpha2}</Ctry>
|
||||||
</PstlAdr>
|
</PstlAdr>
|
||||||
</Cdtr>
|
</Cdtr>
|
||||||
<CdtrAcct><Id><IBAN>{tx.Member.Iban}</IBAN></Id><CdtrAcct>
|
<CdtrAcct><Id><IBAN>{tx.Member.Iban}</IBAN></Id></CdtrAcct>
|
||||||
<CdtrAgt><FinInstnId><BICFI>{tx.Member.Bic ?? "NOTPROVIDED"}</BICFI></FinInstnId></CdtrAgt>
|
<CdtrAgt><FinInstnId><BICFI>{tx.Member.Bic ?? "NOTPROVIDED"}</BICFI></FinInstnId></CdtrAgt>
|
||||||
<RmtInf><Ustrd>{info}</Ustrd></RmtInf>
|
<RmtInf><Ustrd>{info}</Ustrd></RmtInf>
|
||||||
</CdtTrfTxInf>
|
</CdtTrfTxInf>
|
||||||
""");
|
""");
|
||||||
progress?.Report(100.0 * ++i / count);
|
progress?.Report(100.0 * ++i / count);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _writer.WriteLineAsync("""
|
await Writer.WriteLineAsync("""
|
||||||
</PmtInf>
|
</PmtInf>
|
||||||
</CstmrCdtTrfInitn>
|
</CstmrCdtTrfInitn>
|
||||||
</Document>
|
</Document>
|
||||||
""");
|
""");
|
||||||
await _writer.FlushAsync();
|
await Writer.FlushAsync();
|
||||||
progress?.Report(100.0);
|
progress?.Report(100.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using Elwig.Helpers.Billing;
|
using Elwig.Models.Dtos;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Elwig.Helpers.Export {
|
namespace Elwig.Helpers.Export {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using Elwig.Helpers.Billing;
|
using Elwig.Models.Dtos;
|
||||||
|
|
||||||
namespace Elwig.Helpers.Export {
|
namespace Elwig.Helpers.Export {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
26
Elwig/Models/Dtos/Transaction.cs
Normal file
26
Elwig/Models/Dtos/Transaction.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using Elwig.Models.Entities;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Elwig.Models.Dtos {
|
||||||
|
public class Transaction(Member member, decimal amount, string currency, int nr) {
|
||||||
|
|
||||||
|
public readonly Member Member = member;
|
||||||
|
public readonly decimal Amount = amount;
|
||||||
|
public readonly string Currency = currency;
|
||||||
|
public readonly int Nr = nr;
|
||||||
|
|
||||||
|
public Transaction(Credit c) : this(c.Member, c.Amount, c.Variant.Season.CurrencyCode, c.TgNr) { }
|
||||||
|
|
||||||
|
public static IEnumerable<Transaction> FromPaymentVariant(PaymentVar variant) {
|
||||||
|
return variant.Credits
|
||||||
|
.OrderBy(c => c.TgNr)
|
||||||
|
.Select(c => new Transaction(c))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FormatAmountCent(long cents) => $"{cents / 100}.{cents % 100:00}";
|
||||||
|
|
||||||
|
public static string FormatAmount(decimal amount) => FormatAmountCent((int)(amount * 100));
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user