Billing: Calculate prices

This commit is contained in:
2023-11-30 01:44:48 +01:00
parent 17d00a8524
commit 8b9d62ea50
7 changed files with 61 additions and 23 deletions

View File

@ -13,11 +13,11 @@
<col style="width: 18mm;"/> <col style="width: 18mm;"/>
<col style="width: 10mm;"/> <col style="width: 10mm;"/>
<col style="width: 10mm;"/> <col style="width: 10mm;"/>
<col style="width: 10mm;"/>
<col style="width: 10mm;"/>
<col style="width: 15mm;"/> <col style="width: 15mm;"/>
<col style="width: 12mm;"/> <col style="width: 12mm;"/>
<col style="width: 15mm;"/> <col style="width: 15mm;"/>
<col style="width: 10mm;"/>
<col style="width: 10mm;"/>
<col style="width: 15mm;"/> <col style="width: 15mm;"/>
</colgroup> </colgroup>
<thead> <thead>
@ -27,21 +27,21 @@
<th rowspan="3" style="text-align: left;">Sorte</th> <th rowspan="3" style="text-align: left;">Sorte</th>
<th rowspan="3" style="text-align: left;">Attribut</th> <th rowspan="3" style="text-align: left;">Attribut</th>
<th rowspan="2" colspan="2">Gradation</th> <th rowspan="2" colspan="2">Gradation</th>
<th colspan="2">Zu-/Abschläge</th>
<th rowspan="2" colspan="2">Flächenbindung</th> <th rowspan="2" colspan="2">Flächenbindung</th>
<th rowspan="2">Preis</th> <th rowspan="2">Preis</th>
<th colspan="2">Zu-/Abschläge</th>
<th rowspan="2">Betrag</th> <th rowspan="2">Betrag</th>
</tr> </tr>
<tr> <tr>
<th>Abs.</th>
<th>Rel.</th> <th>Rel.</th>
<th>Abs.</th>
</tr> </tr>
<tr> <tr>
<th>[°Oe]</th> <th>[°Oe]</th>
<th>[°KMW]</th> <th>[°KMW]</th>
<th colspan="2">[kg]</th>
<th>[@Model.CurrencySymbol/kg]</th> <th>[@Model.CurrencySymbol/kg]</th>
<th>[%]</th> <th>[%]</th>
<th colspan="2">[kg]</th>
<th>[@Model.CurrencySymbol/kg]</th> <th>[@Model.CurrencySymbol/kg]</th>
<th>[@Model.CurrencySymbol]</th> <th>[@Model.CurrencySymbol]</th>
</tr> </tr>
@ -62,8 +62,6 @@
<td class="attribute small">@p.Attribute</td> <td class="attribute small">@p.Attribute</td>
<td rowspan="@rows" class="oe">@($"{p.Gradation.Oe:N0}")</td> <td rowspan="@rows" class="oe">@($"{p.Gradation.Oe:N0}")</td>
<td rowspan="@rows" class="kmw">@($"{p.Gradation.Kmw:N1}")</td> <td rowspan="@rows" class="kmw">@($"{p.Gradation.Kmw:N1}")</td>
<td rowspan="@rows" class="abs">@abs</td>
<td rowspan="@rows" class="rel">@rel</td>
} }
@if (i > 0 && i <= p.Modifiers.Length) { @if (i > 0 && i <= p.Modifiers.Length) {
<td colspan="2" class="mod">@(p.Modifiers[i - 1])</td> <td colspan="2" class="mod">@(p.Modifiers[i - 1])</td>
@ -79,7 +77,10 @@
<td colspan="3"></td> <td colspan="3"></td>
} }
@if (first) { @if (first) {
<td rowspan="@rows" class="amount">@($"{1000:N2}")</td> <td rowspan="@rows" class="rel">@rel</td>
<td rowspan="@rows" class="abs">@abs</td>
<!-- FIXME rel/abs mods -->
<td rowspan="@rows" class="amount">@($"{p.Buckets.Sum(b => b.Amount):N2}")</td>
first = false; first = false;
} }
</tr> </tr>

View File

@ -32,7 +32,8 @@ table.credit .dpnr {
} }
table.credit .amount, table.credit .amount,
table.credit .weight { table.credit .weight,
table.credit .price {
text-align: right; text-align: right;
} }

View File

@ -689,7 +689,7 @@ namespace Elwig.Helpers {
BEGIN BEGIN
INSERT INTO payment_member (year, avnr, mgnr, net_amount) INSERT INTO payment_member (year, avnr, mgnr, net_amount)
VALUES (NEW.year, NEW.avnr, (SELECT mgnr FROM delivery WHERE (year, did) = (NEW.year, NEW.did)), NEW.amount) VALUES (NEW.year, NEW.avnr, (SELECT mgnr FROM delivery WHERE (year, did) = (NEW.year, NEW.did)), NEW.amount)
ON CONFLICT DO UPDATE SET amount = amount + excluded.amount; ON CONFLICT DO UPDATE SET net_amount = net_amount + excluded.net_amount;
END; END;
"""); """);
ExecuteNonQuery(cnx, """ ExecuteNonQuery(cnx, """

View File

@ -1,4 +1,3 @@
using Microsoft.Data.Sqlite;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;

View File

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Elwig.Helpers.Billing { namespace Elwig.Helpers.Billing {
@ -15,6 +13,10 @@ namespace Elwig.Helpers.Billing {
protected async Task DeleteInDb() { protected async Task DeleteInDb() {
using var cnx = await AppDbContext.ConnectAsync(); using var cnx = await AppDbContext.ConnectAsync();
using (var cmd = cnx.CreateCommand()) {
cmd.CommandText = $"DELETE FROM payment_delivery_part_bucket WHERE (year, avnr) = ({Year}, {AvNr})";
await cmd.ExecuteNonQueryAsync();
}
using (var cmd = cnx.CreateCommand()) { using (var cmd = cnx.CreateCommand()) {
cmd.CommandText = $"DELETE FROM payment_delivery_part WHERE (year, avnr) = ({Year}, {AvNr})"; cmd.CommandText = $"DELETE FROM payment_delivery_part WHERE (year, avnr) = ({Year}, {AvNr})";
await cmd.ExecuteNonQueryAsync(); await cmd.ExecuteNonQueryAsync();
@ -27,15 +29,41 @@ namespace Elwig.Helpers.Billing {
public async Task CalculatePrices() { public async Task CalculatePrices() {
await DeleteInDb(); await DeleteInDb();
var tasks = new List<Task>(); using var cnx = await AppDbContext.ConnectAsync();
foreach (var mgnr in Context.Members.Select(m => m.MgNr)) {
tasks.Add(Task.Run(() => CalculateMemberPrices(mgnr))); var parts = new List<(int Year, int DId, int DPNr, int BktNr, string SortId, string Discr, int Value, bool MinQuw, double Oe, double Kmw)>();
using (var cmd = cnx.CreateCommand()) {
cmd.CommandText = $"""
SELECT d.year, d.did, d.dpnr, b.bktnr, d.sortid, b.discr, b.value, d.min_quw, d.oe, d.kmw
FROM delivery_part_bucket b
JOIN v_delivery d ON (d.year, d.did, d.dpnr) = (b.year, b.did, b.dpnr)
WHERE b.year = {Year}
""";
using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync()) {
parts.Add((
reader.GetInt32(0), reader.GetInt32(1), reader.GetInt32(2), reader.GetInt32(3),
reader.GetString(4), reader.GetString(5), reader.GetInt32(6),
reader.GetBoolean(7), reader.GetDouble(8), reader.GetDouble(9)
));
}
} }
await Task.WhenAll(tasks);
}
protected async Task CalculateMemberPrices(int mgnr) { var inserts = new List<(int Year, int DId, int DPNr, int BktNr, long Price, long Amount)>();
foreach (var part in parts) {
var price = !part.MinQuw ? 0.5m : ((part.BktNr == 2 ? 0.8m : (part.BktNr == 1 ? 0.7m : 0.6m)) + ((decimal)(part.Oe - 73) * 0.005m)); // TODO
var priceL = Utils.DecToDb(price, 4);
var amount = Utils.DecToDb(price * part.Value, 4);
inserts.Add((part.Year, part.DId, part.DPNr, part.BktNr, priceL, amount));
}
using (var cmd = cnx.CreateCommand()) {
cmd.CommandText = $"""
INSERT INTO payment_delivery_part_bucket (year, did, dpnr, bktnr, avnr, price, amount)
VALUES {string.Join(",\n ", inserts.Select(i => $"({i.Year}, {i.DId}, {i.DPNr}, {i.BktNr}, {AvNr}, {i.Price}, {i.Amount})"))}
""";
await cmd.ExecuteNonQueryAsync();
}
} }
} }
} }

View File

@ -90,9 +90,10 @@ namespace Elwig.Models.Dtos {
Buckets = rows Buckets = rows
.Where(b => b.Value > 0) .Where(b => b.Value > 0)
.OrderByDescending(b => b.BktNr) .OrderByDescending(b => b.BktNr)
// FIXME precision
.Select(b => (b.Discr == "_" ? "ungeb." : $"geb. {f.SortId}{b.Discr}", b.Value, .Select(b => (b.Discr == "_" ? "ungeb." : $"geb. {f.SortId}{b.Discr}", b.Value,
b.Price != null ? (decimal?)Utils.DecFromDb((long)b.Price, 0) : null, b.Price != null ? (decimal?)Utils.DecFromDb((long)b.Price, 4) : null,
b.Amount != null ? (decimal?)Utils.DecFromDb((long)b.Amount, 0) : null)) b.Amount != null ? (decimal?)Utils.DecFromDb((long)b.Amount, 4) : null))
.ToArray(); .ToArray();
} }
} }

View File

@ -10,6 +10,7 @@ using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using Elwig.Helpers.Billing;
namespace Elwig.Windows { namespace Elwig.Windows {
public partial class PaymentVariantsWindow : ContextWindow { public partial class PaymentVariantsWindow : ContextWindow {
@ -68,8 +69,15 @@ namespace Elwig.Windows {
} }
private void CalculateButton_Click(object sender, RoutedEventArgs evt) { private async void CalculateButton_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedValue is not PaymentVar v)
return;
CalculateButton.IsEnabled = false;
Mouse.OverrideCursor = Cursors.AppStarting;
var b = new BillingVariant(v.Year, v.AvNr);
await b.CalculatePrices();
Mouse.OverrideCursor = null;
CalculateButton.IsEnabled = true;
} }
private void EditButton_Click(object sender, RoutedEventArgs evt) { private void EditButton_Click(object sender, RoutedEventArgs evt) {