diff --git a/Elwig/Documents/CreditNote.cs b/Elwig/Documents/CreditNote.cs
index 31160bd..544d2e0 100644
--- a/Elwig/Documents/CreditNote.cs
+++ b/Elwig/Documents/CreditNote.cs
@@ -1,6 +1,7 @@
 using Elwig.Helpers;
 using Elwig.Models.Dtos;
 using Elwig.Models.Entities;
+using System.Collections.Generic;
 using System.Linq;
 
 namespace Elwig.Documents {
@@ -13,8 +14,9 @@ namespace Elwig.Documents {
         public string CurrencySymbol;
         public int Precision;
         public string MemberModifier;
+        public IEnumerable<(string Name, int Kg, decimal Amount)>? MemberUnderDeliveries;
 
-        public CreditNote(AppDbContext ctx, PaymentMember p, CreditNoteData data) :
+        public CreditNote(AppDbContext ctx, PaymentMember p, CreditNoteData data, Dictionary<string, UnderDelivery>? underDeliveries = null) :
             base($"Traubengutschrift {(p.Credit != null ? $"Nr. {p.Credit.Year}/{p.Credit.TgNr:000}" : p.Member.Name)} – {p.Variant.Name}", p.Member) {
             UseBillingAddress = true;
             ShowDateAndLocation = true;
@@ -38,5 +40,19 @@ namespace Elwig.Documents {
             DocumentId = $"Tr.-Gutschr. " + (p.Credit != null ? $"{p.Credit.Year}/{p.Credit.TgNr:000}" : p.MgNr);
             CurrencySymbol = season.Currency.Symbol ?? season.Currency.Code;
             Precision = season.Precision;
+
+            var variants = ctx.WineVarieties.ToDictionary(v => v.SortId, v => v);
+            var attributes = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a);
+            var comTypes = ctx.AreaCommitmentTypes.ToDictionary(t => t.VtrgId, t => t);
+            MemberUnderDeliveries = underDeliveries?
+                .OrderBy(u => u.Key)
+                .Select(u => (
+                    variants[u.Key[..2]].Name + (u.Key.Length > 2 ? " " + attributes[u.Key[2..]].Name : ""),
+                    u.Value.Diff,
+                    u.Value.Diff * (comTypes[u.Key].PenaltyPerKg ?? 0)
+                      - (comTypes[u.Key].PenaltyAmount ?? 0)
+                      - ((u.Value.Weight == 0 ? comTypes[u.Key].PenaltyNone : null) ?? 0)))
+                .Where(u => u.Item3 != 0)
+                .ToList();
         }
     }}
diff --git a/Elwig/Documents/CreditNote.cshtml b/Elwig/Documents/CreditNote.cshtml
index 4e78032..3d98f80 100644
--- a/Elwig/Documents/CreditNote.cshtml
+++ b/Elwig/Documents/CreditNote.cshtml
@@ -79,12 +79,12 @@
             }
         </tbody>
         @{
-            string FormatRow(string name, decimal? value, bool add = false, bool halfLine = true, bool bold = false) {
+            string FormatRow(string name, decimal? value, bool add = false, bool halfLine = true, bool bold = false, bool subCat = false) {
                 return $"<tr class=\"{(halfLine || add ? "" : "sum")} {(bold ? "large bold" : "")}\">"
                      + $"<td colspan=\"4\"></td>"
-                     + $"<td class=\"{(halfLine && !add ? "sum" : "")}\" colspan=\"4\">{name}:</td>"
-                     + $"<td class=\"number large {(halfLine && !add ? "sum" : "")}\">{(value < 0 ? "–" : (add ? "+" : ""))}</td>"
-                     + $"<td colspan=\"2\" class=\"number large {(halfLine && !add ? "sum" : "")}\">"
+                     + $"<td class=\"{(halfLine && !add ? "sum" : "")} {(subCat ? "small" : "")}\" colspan=\"4\" style=\"overflow: visible;\">{name}:</td>"
+                     + $"<td class=\"number {(subCat ? "small" : "large")} {(halfLine && !add ? "sum" : "")}\">{(value < 0 ? "–" : (add ? "+" : ""))}</td>"
+                     + $"<td colspan=\"2\" class=\"number {(subCat ? "small" : "large")} {(halfLine && !add ? "sum" : "")}\">"
                      +   $"<span class=\"fleft\">{Model.CurrencySymbol}</span>{Math.Abs(value ?? 0):N2}</td>"
                      + $"</tr>\n";
             }
@@ -116,5 +116,33 @@
                 }
             }
         </tbody>
+        <tbody style="break-inside: avoid;">
+            @{ decimal penalty = 0; }
+
+            @if (Model.MemberUnderDeliveries != null && Model.MemberUnderDeliveries.Count() > 0) {
+                <tr class="small">
+                    <td colspan="4"></td>
+                    <td colspan="5" style="padding-top: 5mm;">Anfallende Pönalen durch Unterlieferungen:</td>
+                    <td colspan="2"></td>
+                </tr>
+                foreach (var u in Model.MemberUnderDeliveries) {
+                    @Raw(FormatRow($"{u.Name} ({u.Kg:N0} kg)", u.Amount, add: true, subCat: true))
+                    penalty += u.Amount;
+                }
+                penalty = Math.Round(penalty, 2, MidpointRounding.AwayFromZero);
+            }
+
+            @if (Model.Credit == null) {
+                @Raw(FormatRow("Auszahlungsbetrag", (Model.Payment?.Amount + penalty) ?? (sum + penalty), bold: true))
+            } else {
+                if (Model.Credit.Modifiers - penalty != 0) {
+                    @Raw(FormatRow("Weitere Abzüge", Model.Credit.Modifiers - penalty, add: true))
+                }
+                if (Model.Credit.PrevModifiers != null && Model.Credit.PrevModifiers != 0) {
+                    @Raw(FormatRow("Bereits berücksichtigte Abzüge", -Model.Credit.PrevModifiers, add: true))
+                }
+                @Raw(FormatRow("Auszahlungsbetrag", Model.Credit.Amount, bold: true))
+            }
+        </tbody>
     </table>
 </main>
diff --git a/Elwig/Helpers/AppDbContext.cs b/Elwig/Helpers/AppDbContext.cs
index 87b2a95..06ed0b7 100644
--- a/Elwig/Helpers/AppDbContext.cs
+++ b/Elwig/Helpers/AppDbContext.cs
@@ -14,6 +14,7 @@ using Elwig.Models.Dtos;
 namespace Elwig.Helpers {
 
     public record struct AreaComBucket(int Area, int Obligation, int Right);
+    public record struct UnderDelivery(int Weight, int Diff);
     public record struct MemberBucket(string Name, int Area, int Obligation, int Right, int Delivery, int DeliveryStrict, int Payment);
 
     public class AppDbContext : DbContext {
@@ -64,10 +65,11 @@ namespace Elwig.Helpers {
 
         public static string ConnectionString => $"Data Source=\"{App.Config.DatabaseFile}\"; Foreign Keys=True; Mode=ReadWrite; Cache=Default";
 
-        private readonly Dictionary<int, Dictionary<int, Dictionary<string, AreaComBucket>>> _memberAreaCommitmentBuckets = new();
-        private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBuckets = new();
-        private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBucketsStrict = new();
-        private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberPaymentBuckets = new();
+        private readonly Dictionary<int, Dictionary<int, Dictionary<string, AreaComBucket>>> _memberAreaCommitmentBuckets = [];
+        private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBuckets = [];
+        private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBucketsStrict = [];
+        private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberPaymentBuckets = [];
+        private readonly Dictionary<int, Dictionary<int, Dictionary<string, UnderDelivery>>> _memberUnderDelivery = [];
 
         public AppDbContext() {
             if (App.Config.DatabaseLog != null) {
@@ -217,7 +219,7 @@ namespace Elwig.Helpers {
                 while (await reader.ReadAsync()) {
                     var mgnr = reader.GetInt32(0);
                     var vtrgid = reader.GetString(1);
-                    if (!buckets.ContainsKey(mgnr)) buckets[mgnr] = new();
+                    if (!buckets.ContainsKey(mgnr)) buckets[mgnr] = [];
                     buckets[mgnr][vtrgid] = new(reader.GetInt32(2), reader.GetInt32(3), reader.GetInt32(4));
                 }
             }
@@ -235,7 +237,7 @@ namespace Elwig.Helpers {
                 while (await reader.ReadAsync()) {
                     var mgnr = reader.GetInt32(0);
                     var bucket = reader.GetString(1);
-                    if (!buckets.ContainsKey(mgnr)) buckets[mgnr] = new();
+                    if (!buckets.ContainsKey(mgnr)) buckets[mgnr] = [];
                     buckets[mgnr][bucket] = reader.GetInt32(2);
                 }
             }
@@ -253,7 +255,7 @@ namespace Elwig.Helpers {
                 while (await reader.ReadAsync()) {
                     var mgnr = reader.GetInt32(0);
                     var bucket = reader.GetString(1);
-                    if (!buckets.ContainsKey(mgnr)) buckets[mgnr] = new();
+                    if (!buckets.ContainsKey(mgnr)) buckets[mgnr] = [];
                     buckets[mgnr][bucket] = reader.GetInt32(2);
                 }
             }
@@ -271,7 +273,7 @@ namespace Elwig.Helpers {
                 while (await reader.ReadAsync()) {
                     var mgnr = reader.GetInt32(0);
                     var bucket = reader.GetString(1);
-                    if (!buckets.ContainsKey(mgnr)) buckets[mgnr] = new();
+                    if (!buckets.ContainsKey(mgnr)) buckets[mgnr] = [];
                     buckets[mgnr][bucket] = reader.GetInt32(2);
                 }
             }
@@ -279,28 +281,52 @@ namespace Elwig.Helpers {
             _memberPaymentBuckets[year] = buckets;
         }
 
+        private async Task FetchMemberUnderDelivery(int year, SqliteConnection? cnx = null) {
+            var ownCnx = cnx == null;
+            cnx ??= await ConnectAsync();
+            var buckets = new Dictionary<int, Dictionary<string, UnderDelivery>>();
+            using (var cmd = cnx.CreateCommand()) {
+                cmd.CommandText = $"SELECT mgnr, bucket, weight, diff FROM v_under_delivery WHERE year = {year}";
+                using var reader = await cmd.ExecuteReaderAsync();
+                while (await reader.ReadAsync()) {
+                    var mgnr = reader.GetInt32(0);
+                    var bucket = reader.GetString(1);
+                    if (!buckets.ContainsKey(mgnr)) buckets[mgnr] = [];
+                    buckets[mgnr][bucket] = new(reader.GetInt32(2), reader.GetInt32(3));
+                }
+            }
+            if (ownCnx) await cnx.DisposeAsync();
+            _memberUnderDelivery[year] = buckets;
+        }
+
         public async Task<Dictionary<string, AreaComBucket>> GetMemberAreaCommitmentBuckets(int year, int mgnr, SqliteConnection? cnx = null) {
             if (!_memberAreaCommitmentBuckets.ContainsKey(year))
                 await FetchMemberAreaCommitmentBuckets(year, cnx);
-            return _memberAreaCommitmentBuckets[year].GetValueOrDefault(mgnr, new());
+            return _memberAreaCommitmentBuckets[year].GetValueOrDefault(mgnr, []);
         }
 
         public async Task<Dictionary<string, int>> GetMemberDeliveryBuckets(int year, int mgnr, SqliteConnection? cnx = null) {
             if (!_memberDeliveryBuckets.ContainsKey(year))
                 await FetchMemberDeliveryBuckets(year, cnx);
-            return _memberDeliveryBuckets[year].GetValueOrDefault(mgnr, new());
+            return _memberDeliveryBuckets[year].GetValueOrDefault(mgnr, []);
         }
 
         public async Task<Dictionary<string, int>> GetMemberDeliveryBucketsStrict(int year, int mgnr, SqliteConnection? cnx = null) {
             if (!_memberDeliveryBucketsStrict.ContainsKey(year))
                 await FetchMemberDeliveryBucketsStrict(year, cnx);
-            return _memberDeliveryBucketsStrict[year].GetValueOrDefault(mgnr, new());
+            return _memberDeliveryBucketsStrict[year].GetValueOrDefault(mgnr, []);
         }
 
         public async Task<Dictionary<string, int>> GetMemberPaymentBuckets(int year, int mgnr, SqliteConnection? cnx = null) {
             if (!_memberPaymentBuckets.ContainsKey(year))
                 await FetchMemberPaymentBuckets(year, cnx);
-            return _memberPaymentBuckets[year].GetValueOrDefault(mgnr, new());
+            return _memberPaymentBuckets[year].GetValueOrDefault(mgnr, []);
+        }
+
+        public async Task<Dictionary<string, UnderDelivery>> GetMemberUnderDelivery(int year, int mgnr, SqliteConnection? cnx = null) {
+            if (!_memberUnderDelivery.ContainsKey(year))
+                await FetchMemberUnderDelivery(year, cnx);
+            return _memberUnderDelivery[year].GetValueOrDefault(mgnr, []);
         }
 
         public async Task<Dictionary<string, MemberBucket>> GetMemberBuckets(int year, int mgnr, SqliteConnection? cnx = null) {
diff --git a/Elwig/Helpers/Billing/BillingVariant.cs b/Elwig/Helpers/Billing/BillingVariant.cs
index 7f86782..79a1797 100644
--- a/Elwig/Helpers/Billing/BillingVariant.cs
+++ b/Elwig/Helpers/Billing/BillingVariant.cs
@@ -23,18 +23,17 @@ namespace Elwig.Helpers.Billing {
             await Revert();
             using var cnx = await AppDbContext.ConnectAsync();
             using (var cmd = cnx.CreateCommand()) {
-                // TODO modifiers and prev_modifiers
                 cmd.CommandText = $"""
                     INSERT INTO credit (year, tgnr, mgnr, avnr, net_amount, prev_net_amount, vat, modifiers, prev_modifiers)
                     SELECT s.year,
                            COALESCE(t.tgnr, 0) + ROW_NUMBER() OVER(ORDER BY m.mgnr) AS tgnr,
                            m.mgnr,
                            v.avnr,
-                           ROUND(p.amount / POW(10, s.precision - 2)),
+                           ROUND(p.amount / POW(10, s.precision - 2)) AS net_amount,
                            ROUND(lp.amount / POW(10, s.precision - 2)) AS prev_amount,
                            IIF(m.buchführend, s.vat_normal, s.vat_flatrate) AS vat,
-                           NULL,
-                           NULL
+                           ROUND(COALESCE(u.total_penalty, 0) / POW(10, 4 - 2)) AS modifiers,
+                           lc.modifiers AS prev_modifiers
                     FROM season s
                         JOIN payment_variant v ON v.year = s.year
                         LEFT JOIN payment_variant l ON l.year = s.year
@@ -48,6 +47,14 @@ namespace Elwig.Helpers.Billing {
                         JOIN member m ON m.mgnr = d.mgnr
                         LEFT JOIN payment_member lp ON (lp.year, lp.avnr, lp.mgnr) = (l.year, l.avnr, m.mgnr)
                         LEFT JOIN payment_member p ON (p.year, p.avnr, p.mgnr) = (v.year, v.avnr, m.mgnr)
+                        LEFT JOIN credit lc ON (lc.year, lc.avnr, lc.mgnr) = (l.year, l.avnr, m.mgnr)
+                        LEFT JOIN (SELECT year, mgnr,
+                                          SUM(COALESCE(IIF(u.weight = 0, -t.penalty_none, 0), 0) +
+                                              COALESCE(IIF(u.diff < 0, -t.penalty_amount, 0), 0) +
+                                              COALESCE(u.diff * t.penalty_per_kg, 0)) AS total_penalty
+                                   FROM v_under_delivery u
+                                       JOIN area_commitment_type t ON t.vtrgid = u.bucket
+                                   GROUP BY year, mgnr) u ON (u.year, u.mgnr) = (s.year, m.mgnr)
                     WHERE s.year = {Year} AND v.avnr = {AvNr}
                     """;
                 await cmd.ExecuteNonQueryAsync();
diff --git a/Elwig/Windows/PaymentVariantsWindow.xaml.cs b/Elwig/Windows/PaymentVariantsWindow.xaml.cs
index 8b3d9bf..c3cf985 100644
--- a/Elwig/Windows/PaymentVariantsWindow.xaml.cs
+++ b/Elwig/Windows/PaymentVariantsWindow.xaml.cs
@@ -140,8 +140,9 @@ namespace Elwig.Windows {
             IEnumerable<Member> list = await members.ToListAsync();
             var data = await CreditNoteData.ForPaymentVariant(Context.CreditNoteRows, Context.Seasons, v.Year, v.AvNr);
             var payments = await Context.MemberPayments.Where(p => p.Year == v.Year && p.AvNr == v.AvNr).ToDictionaryAsync(c => c.MgNr);
+            await Context.GetMemberAreaCommitmentBuckets(Year, 0);
             using var doc = Document.Merge(list.Select(m =>
-                new CreditNote(Context, payments[m.MgNr], data[m.MgNr])
+                new CreditNote(Context, payments[m.MgNr], data[m.MgNr], Context.GetMemberUnderDelivery(Year, m.MgNr).GetAwaiter().GetResult())
             ));
             await doc.Generate(new Progress<double>(v => {
                 ProgressBar.Value = v;