DataTable: Add units for columns
This commit is contained in:
		@@ -54,8 +54,8 @@
 | 
				
			|||||||
                            <td class="small">@p.Variant</td>
 | 
					                            <td class="small">@p.Variant</td>
 | 
				
			||||||
                            <td class="small">@p.Attribute</td>
 | 
					                            <td class="small">@p.Attribute</td>
 | 
				
			||||||
                            <td class="small">@p.QualityLevel</td>
 | 
					                            <td class="small">@p.QualityLevel</td>
 | 
				
			||||||
                            <td rowspan="@rows" class="grad">@($"{p.Oe:N0}")</td>
 | 
					                            <td rowspan="@rows" class="grad">@($"{p.Gradation.Oe:N0}")</td>
 | 
				
			||||||
                            <td rowspan="@rows" class="grad">@($"{p.Kmw:N1}")</td>
 | 
					                            <td rowspan="@rows" class="grad">@($"{p.Gradation.Kmw:N1}")</td>
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        @if (i > 0 && i <= p.Modifiers.Length) {
 | 
					                        @if (i > 0 && i <= p.Modifiers.Length) {
 | 
				
			||||||
                            <td colspan="3" class="mod">@(p.Modifiers[i - 1])</td>
 | 
					                            <td colspan="3" class="mod">@(p.Modifiers[i - 1])</td>
 | 
				
			||||||
@@ -64,8 +64,8 @@
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        @if (i < p.Buckets.Length) {
 | 
					                        @if (i < p.Buckets.Length) {
 | 
				
			||||||
                            var bucket = p.Buckets[i];
 | 
					                            var bucket = p.Buckets[i];
 | 
				
			||||||
                            <td class="geb">@bucket.Item1:</td>
 | 
					                            <td class="geb">@bucket.Name:</td>
 | 
				
			||||||
                            <td class="weight">@($"{bucket.Item2:N0}")</td>
 | 
					                            <td class="weight">@($"{bucket.Value:N0}")</td>
 | 
				
			||||||
                        } else {
 | 
					                        } else {
 | 
				
			||||||
                            <td colspan="2"></td>
 | 
					                            <td colspan="2"></td>
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -81,7 +81,7 @@ namespace Elwig.Helpers.Export {
 | 
				
			|||||||
            Content = new StreamWriter(content.Open(), Utils.UTF8);
 | 
					            Content = new StreamWriter(content.Open(), Utils.UTF8);
 | 
				
			||||||
            await Content.WriteAsync("""
 | 
					            await Content.WriteAsync("""
 | 
				
			||||||
                <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 | 
					                <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 | 
				
			||||||
                <office:document-content xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" office:version="1.3">
 | 
					                <office:document-content xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" office:version="1.3">
 | 
				
			||||||
                 <office:automatic-styles>
 | 
					                 <office:automatic-styles>
 | 
				
			||||||
                  <style:default-style style:family="table-cell">
 | 
					                  <style:default-style style:family="table-cell">
 | 
				
			||||||
                   <style:text-properties fo:language="de" fo:country="AT"/>
 | 
					                   <style:text-properties fo:language="de" fo:country="AT"/>
 | 
				
			||||||
@@ -108,10 +108,14 @@ namespace Elwig.Helpers.Export {
 | 
				
			|||||||
                   <style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"  fo:font-size="16pt"/>
 | 
					                   <style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"  fo:font-size="16pt"/>
 | 
				
			||||||
                  </style:style>
 | 
					                  </style:style>
 | 
				
			||||||
                  <style:style style:name="th" style:family="table-cell" style:parent-style-name="default">
 | 
					                  <style:style style:name="th" style:family="table-cell" style:parent-style-name="default">
 | 
				
			||||||
                   <style:table-cell-properties style:text-align-source="fix" style:repeat-content="false"/>
 | 
					                   <style:table-cell-properties style:text-align-source="fix" style:repeat-content="false" style:vertical-align="middle"/>
 | 
				
			||||||
                   <style:paragraph-properties fo:text-align="center"/>
 | 
					                   <style:paragraph-properties fo:text-align="center"/>
 | 
				
			||||||
                   <style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"/>
 | 
					                   <style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"/>
 | 
				
			||||||
                  </style:style>
 | 
					                  </style:style>
 | 
				
			||||||
 | 
					                  <number:number-style style:name="nperc">
 | 
				
			||||||
 | 
					                   <number:number number:decimal-places="1" number:min-decimal-places="1" number:min-integer-digits="1"/>
 | 
				
			||||||
 | 
					                  </number:number-style>
 | 
				
			||||||
 | 
					                  <style:style style:name="perc" style:family="table-cell" style:parent-style-name="default" style:data-style-name="nperc"/>
 | 
				
			||||||
                 </office:automatic-styles>
 | 
					                 </office:automatic-styles>
 | 
				
			||||||
                 <office:body>
 | 
					                 <office:body>
 | 
				
			||||||
                  <office:spreadsheet>
 | 
					                  <office:spreadsheet>
 | 
				
			||||||
@@ -151,8 +155,8 @@ namespace Elwig.Helpers.Export {
 | 
				
			|||||||
                    await writer.WriteAsync($"""
 | 
					                    await writer.WriteAsync($"""
 | 
				
			||||||
                              <config:config-item-map-entry config:name="{tbl}">
 | 
					                              <config:config-item-map-entry config:name="{tbl}">
 | 
				
			||||||
                               <config:config-item config:name="VerticalSplitMode" config:type="short">2</config:config-item>
 | 
					                               <config:config-item config:name="VerticalSplitMode" config:type="short">2</config:config-item>
 | 
				
			||||||
                               <config:config-item config:name="VerticalSplitPosition" config:type="int">3</config:config-item>
 | 
					                               <config:config-item config:name="VerticalSplitPosition" config:type="int">4</config:config-item>
 | 
				
			||||||
                               <config:config-item config:name="PositionBottom" config:type="int">3</config:config-item>
 | 
					                               <config:config-item config:name="PositionBottom" config:type="int">4</config:config-item>
 | 
				
			||||||
                              </config:config-item-map-entry>
 | 
					                              </config:config-item-map-entry>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        """);
 | 
					                        """);
 | 
				
			||||||
@@ -177,8 +181,10 @@ namespace Elwig.Helpers.Export {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            _tables.Add(table.Name);
 | 
					            _tables.Add(table.Name);
 | 
				
			||||||
            await Content.WriteAsync($"    <table:table table:name=\"{table.Name}\" table:default-cell-style-name=\"default\">\r\n");
 | 
					            await Content.WriteAsync($"    <table:table table:name=\"{table.Name}\" table:default-cell-style-name=\"default\">\r\n");
 | 
				
			||||||
            foreach (var w in table.ColumnWidths) {
 | 
					            foreach (var (s, w) in table.ColumnSpans.Zip(table.ColumnWidths)) {
 | 
				
			||||||
                await Content.WriteAsync("     <table:table-column" + (w != null ? $" table:style-name=\"colw{w}\"" : "") + "/>\r\n");
 | 
					                for (int i = 0; i < s; i++) {
 | 
				
			||||||
 | 
					                    await Content.WriteAsync("     <table:table-column" + (w != null ? $" table:style-name=\"colw{w / s}\"" : "") + "/>\r\n");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            await Content.WriteAsync(
 | 
					            await Content.WriteAsync(
 | 
				
			||||||
@@ -189,48 +195,76 @@ namespace Elwig.Helpers.Export {
 | 
				
			|||||||
                $"      <table:table-cell table:number-columns-repeated=\"{totalSpan}\"/>\r\n" +
 | 
					                $"      <table:table-cell table:number-columns-repeated=\"{totalSpan}\"/>\r\n" +
 | 
				
			||||||
                $"     </table:table-row>\r\n" +
 | 
					                $"     </table:table-row>\r\n" +
 | 
				
			||||||
                $"     <table:table-row>\r\n");
 | 
					                $"     <table:table-row>\r\n");
 | 
				
			||||||
            foreach (var (name, span) in table.ColumnNames.Zip(table.ColumnSpans)) {
 | 
					            foreach (var (name, span, units) in table.ColumnNames.Zip(table.ColumnSpans, table.ColumnUnits)) {
 | 
				
			||||||
                await Content.WriteAsync(FormatCell(name, colSpan: span, style: "th"));
 | 
					                var hasUnits = units.Length > 0;
 | 
				
			||||||
 | 
					                await Content.WriteAsync(FormatCell(name, colSpan: span, rowSpan: hasUnits ? 1 : 2, style: "th"));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            await Content.WriteAsync("     </table:table-row>\r\n     <table:table-row>\r\n");
 | 
				
			||||||
 | 
					            foreach (var (span, units) in table.ColumnSpans.Zip(table.ColumnUnits)) {
 | 
				
			||||||
 | 
					                if (units.Length == 0) {
 | 
				
			||||||
 | 
					                    await Content.WriteAsync($"      <table:covered-table-cell table:number-columns-repeated=\"{span}\"/>\r\n");
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                foreach (var u in units) {
 | 
				
			||||||
 | 
					                    await Content.WriteAsync(FormatCell(u == null ? null : $"[{u}]", style: "th"));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            await Content.WriteAsync("     </table:table-row>\r\n");
 | 
					            await Content.WriteAsync("     </table:table-row>\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            foreach (var row in table.GetData()) {
 | 
					            foreach (var row in table.GetData()) {
 | 
				
			||||||
                await FormatRow(row);
 | 
					                await FormatRow(row, table.ColumnUnits);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            await Content.WriteAsync("    </table:table>\r\n");
 | 
					            await Content.WriteAsync("    </table:table>\r\n");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected async Task FormatRow(IEnumerable<object?> row) {
 | 
					        protected async Task FormatRow(IEnumerable<object?> row, IEnumerable<string?[]?> colUnits) {
 | 
				
			||||||
            if (Content == null) throw new InvalidOperationException();
 | 
					            if (Content == null) throw new InvalidOperationException();
 | 
				
			||||||
            var arrays = row.Where(c => c is Array).Cast<Array>().Select(c => c.Length).ToArray();
 | 
					            var arrays = row.Where(c => c is Array).Cast<Array>().Select(c => c.Length).ToArray();
 | 
				
			||||||
            int rowNum = Math.Max(1, arrays.Length > 0 ? arrays.Max() : 0);
 | 
					            int rowNum = Math.Max(1, arrays.Length > 0 ? arrays.Max() : 0);
 | 
				
			||||||
            for (int i = 0; i < rowNum; i++) {
 | 
					            for (int i = 0; i < rowNum; i++) {
 | 
				
			||||||
                await Content.WriteAsync("     <table:table-row>\r\n");
 | 
					                await Content.WriteAsync("     <table:table-row>\r\n");
 | 
				
			||||||
                foreach (var data in row) {
 | 
					                foreach (var (data, units) in row.Zip(colUnits)) {
 | 
				
			||||||
                    if (data is Array a) {
 | 
					                    if (data is Array a) {
 | 
				
			||||||
                        await Content.WriteAsync(i < a.Length ? FormatCell(a.GetValue(i)) : "      <table:table-cell/>\r\n");
 | 
					                        await Content.WriteAsync(i < a.Length ? FormatCell(a.GetValue(i), units: units) : $"      <table:table-cell tables:number-columns-repeated=\"{GetSubCols(a.GetType().GetElementType())}\"/>\r\n");
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
                        await Content.WriteAsync(i == 0 ? FormatCell(data, rowNum) : "      <table:covered-table-cell/>\r\n");
 | 
					                        await Content.WriteAsync(FormatCell(data, rowSpan: i == 0 ? rowNum : 1, isCovered: i > 0, units: units));
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                await Content.WriteAsync("     </table:table-row>\r\n");
 | 
					                await Content.WriteAsync("     </table:table-row>\r\n");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected static string FormatCell(object? data, int rowSpan = 1, int colSpan = 1, string? style = "default", bool forceString = false) {
 | 
					        private static int GetSubCols(Type? type) {
 | 
				
			||||||
 | 
					            if (type != null && type.IsValueType == true && type.Name.StartsWith("ValueTuple"))
 | 
				
			||||||
 | 
					                return type.GetFields().Length;
 | 
				
			||||||
 | 
					            return 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected static string FormatCell(object? data, int rowSpan = 1, int colSpan = 1, string? style = "default", bool isCovered = false, string?[]? units = null) {
 | 
				
			||||||
            if (data?.GetType().IsValueType == true && data.GetType().Name.StartsWith("ValueTuple"))
 | 
					            if (data?.GetType().IsValueType == true && data.GetType().Name.StartsWith("ValueTuple"))
 | 
				
			||||||
                return string.Join("", data.GetType().GetFields().Select(p => FormatCell(p.GetValue(data), rowSpan, colSpan, style, forceString)));
 | 
					                return string.Join("", data.GetType().GetFields().Zip(units ?? Array.Empty<string?>())
 | 
				
			||||||
 | 
					                    .Select(p => FormatCell(p.First.GetValue(data), rowSpan, colSpan, style, isCovered, new[] { p.Second }))
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var add = (style != null ? $" table:style-name=\"{style}\"" : "") + (rowSpan > 1 || colSpan > 1 ? $" table:number-rows-spanned=\"{rowSpan}\" table:number-columns-spanned=\"{colSpan}\"" : "");
 | 
					            var add = (style != null ? $" table:style-name=\"{style}\"" : "") + (rowSpan > 1 || colSpan > 1 ? $" table:number-rows-spanned=\"{rowSpan}\" table:number-columns-spanned=\"{colSpan}\"" : "");
 | 
				
			||||||
 | 
					            string ct = isCovered ? "table:covered-table-cell" : "table:table-cell";
 | 
				
			||||||
 | 
					            var isPercent = units != null && units.Length > 0 && units[0] == "%";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            string c;
 | 
					            string c;
 | 
				
			||||||
            if (!forceString && data == null) {
 | 
					            if (data == null) {
 | 
				
			||||||
                c = $"<table:table-cell{add}/>";
 | 
					                c = $"<{ct}{add}/>";
 | 
				
			||||||
            } else if (!forceString && (data is float || data is double || data is byte || data is char ||
 | 
					            } else if (data is float || data is double || data is byte || data is char ||
 | 
				
			||||||
                       data is short || data is ushort || data is int || data is uint || data is long || data is ulong)) {
 | 
					                       data is short || data is ushort || data is int || data is uint || data is long || data is ulong) {
 | 
				
			||||||
                c = $"<table:table-cell office:value-type=\"float\" office:value=\"{data.ToString()?.Replace(",", ".")}\"{add}><text:p>{data}</text:p></table:table-cell>";
 | 
					
 | 
				
			||||||
 | 
					                double v = double.Parse(data?.ToString() ?? "0");
 | 
				
			||||||
 | 
					                if (isPercent) {
 | 
				
			||||||
 | 
					                    data = $"{v:N1}";
 | 
				
			||||||
 | 
					                    add = string.Join(" ", add.Split(" ").Select(p => p.StartsWith("table:style-name=") ? "table:style-name=\"perc\"" : p));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                c = $"<{ct} office:value-type=\"float\" calcext:value-type=\"float\" office:value=\"{v.ToString()?.Replace(",", ".")}\"{add}><text:p>{data}</text:p></{ct}>";
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                c = $"<table:table-cell office:value-type=\"string\"{add}><text:p>{data}</text:p></table:table-cell>";
 | 
					                c = $"<{ct} office:value-type=\"string\" calcext:value-type=\"string\"{add}><text:p>{data}</text:p></{ct}>";
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return $"      {c}\r\n" + (colSpan > 1 ? $"      <table:covered-table-cell table:number-rows-repeated=\"{colSpan - 1}\"/>\r\n" : "");
 | 
					            return $"      {c}\r\n" + (colSpan > 1 ? $"      <table:covered-table-cell table:number-rows-repeated=\"{colSpan - 1}\"/>\r\n" : "");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,19 +8,19 @@ using System.Threading.Tasks;
 | 
				
			|||||||
namespace Elwig.Models.Dtos {
 | 
					namespace Elwig.Models.Dtos {
 | 
				
			||||||
    public class AreaComUnderDeliveryData : DataTable<AreaComUnderDeliveryRow> {
 | 
					    public class AreaComUnderDeliveryData : DataTable<AreaComUnderDeliveryRow> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static readonly (string, string, int)[] FieldNames = new[] {
 | 
					        private static readonly (string, string, string?, int)[] FieldNames = new[] {
 | 
				
			||||||
            ("MgNr", "MgNr.", 12),
 | 
					            ("MgNr", "MgNr.", null, 12),
 | 
				
			||||||
            ("Name", "Name", 40),
 | 
					            ("Name", "Name", null, 40),
 | 
				
			||||||
            ("GivenName", "Vorname", 40),
 | 
					            ("GivenName", "Vorname", null, 40),
 | 
				
			||||||
            ("Address", "Adresse", 60),
 | 
					            ("Address", "Adresse", null, 60),
 | 
				
			||||||
            ("Plz", "PLZ", 10),
 | 
					            ("Plz", "PLZ", null, 10),
 | 
				
			||||||
            ("Locality", "Ort", 60),
 | 
					            ("Locality", "Ort", null, 60),
 | 
				
			||||||
            ("VtrgIds", "Vertrag", 14),
 | 
					            ("VtrgIds", "Vertrag", null, 14),
 | 
				
			||||||
            ("Areas", "Fläche", 16),
 | 
					            ("Areas", "Fläche", "m²", 16),
 | 
				
			||||||
            ("DeliveryObligations", "Lieferpflicht", 22),
 | 
					            ("DeliveryObligations", "Lieferpflicht", "kg", 22),
 | 
				
			||||||
            ("Weights", "Geliefert", 22),
 | 
					            ("Weights", "Geliefert", "kg", 22),
 | 
				
			||||||
            ("UnderDeliveries", "Unterliefert", 22),
 | 
					            ("UnderDeliveries", "Unterliefert", "kg", 22),
 | 
				
			||||||
            ("Percents", "Prozent", 16),
 | 
					            ("Percents", "Prozent", "%", 16),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public AreaComUnderDeliveryData(IEnumerable<AreaComUnderDeliveryRow> rows, int year) :
 | 
					        public AreaComUnderDeliveryData(IEnumerable<AreaComUnderDeliveryRow> rows, int year) :
 | 
				
			||||||
@@ -65,7 +65,7 @@ namespace Elwig.Models.Dtos {
 | 
				
			|||||||
            .Select(v => v.First < v.Second ? (int?)v.First - v.Second : null)
 | 
					            .Select(v => v.First < v.Second ? (int?)v.First - v.Second : null)
 | 
				
			||||||
            .ToArray();
 | 
					            .ToArray();
 | 
				
			||||||
        public double?[] Percents => Weights.Zip(DeliveryObligations)
 | 
					        public double?[] Percents => Weights.Zip(DeliveryObligations)
 | 
				
			||||||
            .Select(v => v.First < v.Second ? (double?)Math.Round(v.First * 100.0 / v.Second - 100.0, 1) : null)
 | 
					            .Select(v => v.First < v.Second ? (double?)v.First * 100.0 / v.Second - 100.0 : null)
 | 
				
			||||||
            .ToArray();
 | 
					            .ToArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public AreaComUnderDeliveryRow(IEnumerable<AreaComUnderDeliveryRowSingle> rows) {
 | 
					        public AreaComUnderDeliveryRow(IEnumerable<AreaComUnderDeliveryRowSingle> rows) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,15 +18,16 @@ namespace Elwig.Models.Dtos {
 | 
				
			|||||||
        public IEnumerable<Type?> ColumnFlatTypes { get; private set; }
 | 
					        public IEnumerable<Type?> ColumnFlatTypes { get; private set; }
 | 
				
			||||||
        public IEnumerable<int> ColumnSpans { get; private set; }
 | 
					        public IEnumerable<int> ColumnSpans { get; private set; }
 | 
				
			||||||
        public IEnumerable<int?> ColumnWidths { get; private set; }
 | 
					        public IEnumerable<int?> ColumnWidths { get; private set; }
 | 
				
			||||||
 | 
					        public IEnumerable<string?[]> ColumnUnits { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private readonly PropertyInfo[] _properties;
 | 
					        private readonly PropertyInfo[] _properties;
 | 
				
			||||||
        private readonly FieldInfo[] _fields;
 | 
					        private readonly FieldInfo[] _fields;
 | 
				
			||||||
        private readonly (string, PropertyInfo?, FieldInfo?)[] _map;
 | 
					        private readonly (string, PropertyInfo?, FieldInfo?)[] _map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DataTable(string name, string fullName, IEnumerable<T> rows, IEnumerable<(string, string, int?)>? colNames = null) {
 | 
					        public DataTable(string name, string fullName, IEnumerable<T> rows, IEnumerable<(string, string, string?, int?)>? colNames = null) {
 | 
				
			||||||
            _fields = typeof(T).GetFields();
 | 
					            _fields = typeof(T).GetFields();
 | 
				
			||||||
            _properties = typeof(T).GetProperties();
 | 
					            _properties = typeof(T).GetProperties();
 | 
				
			||||||
            colNames ??= _properties.Select(p => p.Name).Union(_fields.Select(f => f.Name)).Select(i => (i, i, (int?)null)).ToList();
 | 
					            colNames ??= _properties.Select(p => p.Name).Union(_fields.Select(f => f.Name)).Select(i => (i, i, (string?)null, (int?)null)).ToList();
 | 
				
			||||||
            _map = colNames.Select(n => (n.Item2, _properties.FirstOrDefault(p => p?.Name == n.Item1, null), _fields.FirstOrDefault(f => f?.Name == n.Item1, null))).ToArray();
 | 
					            _map = colNames.Select(n => (n.Item2, _properties.FirstOrDefault(p => p?.Name == n.Item1, null), _fields.FirstOrDefault(f => f?.Name == n.Item1, null))).ToArray();
 | 
				
			||||||
            Name = name;
 | 
					            Name = name;
 | 
				
			||||||
            FullName = fullName;
 | 
					            FullName = fullName;
 | 
				
			||||||
@@ -42,27 +43,28 @@ namespace Elwig.Models.Dtos {
 | 
				
			|||||||
                return type != null && type.IsValueType && type.Name.StartsWith("ValueTuple") ? type.GetFields().Length :
 | 
					                return type != null && type.IsValueType && type.Name.StartsWith("ValueTuple") ? type.GetFields().Length :
 | 
				
			||||||
                       type != null && elType != null && type.IsArray && elType.IsValueType && elType.Name.StartsWith("ValueTuple") ? elType.GetFields().Length : 1;
 | 
					                       type != null && elType != null && type.IsArray && elType.IsValueType && elType.Name.StartsWith("ValueTuple") ? elType.GetFields().Length : 1;
 | 
				
			||||||
            }).ToList();
 | 
					            }).ToList();
 | 
				
			||||||
            ColumnWidths = colNames.Select(c => c.Item3).ToList();
 | 
					            ColumnWidths = colNames.Select(c => c.Item4).ToList();
 | 
				
			||||||
 | 
					            ColumnUnits = colNames.Select(c => c.Item3?.Split("|").Select(p => p.Length == 0 ? null : p).ToArray() ?? Array.Empty<string?>()).ToList();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DataTable(string name, string fullName, IEnumerable<T> rows, IEnumerable<(string, string)>? colNames = null) :
 | 
					        public DataTable(string name, string fullName, IEnumerable<T> rows, IEnumerable<(string, string, string?)>? colNames = null) :
 | 
				
			||||||
            this(name, fullName, rows, colNames?.Select(c => (c.Item1, c.Item2, (int?)null))) {
 | 
					            this(name, fullName, rows, colNames?.Select(c => (c.Item1, c.Item2, c.Item3, (int?)null))) {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DataTable(string name, IEnumerable<T> rows, IEnumerable<(string, string)>? colNames = null) :
 | 
					        public DataTable(string name, IEnumerable<T> rows, IEnumerable<(string, string, string?)>? colNames = null) :
 | 
				
			||||||
            this(name, name, rows, colNames) {
 | 
					            this(name, name, rows, colNames) {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DataTable(string name, IEnumerable<T> rows, IEnumerable<(string, string, int?)>? colNames = null) :
 | 
					        public DataTable(string name, IEnumerable<T> rows, IEnumerable<(string, string, string?, int?)>? colNames = null) :
 | 
				
			||||||
            this(name, name, rows, colNames) {
 | 
					            this(name, name, rows, colNames) {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DataTable(string name, IEnumerable<T> rows, IEnumerable<(string, string, int)>? colNames = null) :
 | 
					        public DataTable(string name, IEnumerable<T> rows, IEnumerable<(string, string, string?, int)>? colNames = null) :
 | 
				
			||||||
            this(name, name, rows, colNames) {
 | 
					            this(name, name, rows, colNames) {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DataTable(string name, string fullName, IEnumerable<T> rows, IEnumerable<(string, string, int)>? colNames = null) :
 | 
					        public DataTable(string name, string fullName, IEnumerable<T> rows, IEnumerable<(string, string, string?, int)>? colNames = null) :
 | 
				
			||||||
            this(name, fullName, rows, colNames?.Select(c => (c.Item1, c.Item2, (int?)c.Item3))) {
 | 
					            this(name, fullName, rows, colNames?.Select(c => (c.Item1, c.Item2, c.Item3, (int?)c.Item4))) {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected IEnumerable<(string, object?)> GetNamedRowData(T row) {
 | 
					        protected IEnumerable<(string, object?)> GetNamedRowData(T row) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,17 +7,16 @@ using System.Threading.Tasks;
 | 
				
			|||||||
namespace Elwig.Models.Dtos {
 | 
					namespace Elwig.Models.Dtos {
 | 
				
			||||||
    public class DeliveryConfirmationData : DataTable<DeliveryConfirmationRow> {
 | 
					    public class DeliveryConfirmationData : DataTable<DeliveryConfirmationRow> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static readonly (string, string)[] FieldNames = new[] {
 | 
					        private static readonly (string, string, string?, int)[] FieldNames = new[] {
 | 
				
			||||||
            ("LsNr", "LsNr."),
 | 
					            ("LsNr", "LsNr.", null, 26),
 | 
				
			||||||
            ("DPNr", "Pos."),
 | 
					            ("DPNr", "Pos.", null, 8),
 | 
				
			||||||
            ("Variant", "Sorte"),
 | 
					            ("Variant", "Sorte", null, 40),
 | 
				
			||||||
            ("Attribute", "Attribut"),
 | 
					            ("Attribute", "Attribut", null, 20),
 | 
				
			||||||
            ("Modifiers", "Zu-/Abschläge"),
 | 
					            ("Modifiers", "Zu-/Abschläge", null, 30),
 | 
				
			||||||
            ("QualityLevel", "Qualitätsstufe"),
 | 
					            ("QualityLevel", "Qualitätsstufe", null, 25),
 | 
				
			||||||
            ("Oe", "°Oe"),
 | 
					            ("Gradation", "Gradation", "°Oe|°KMW", 32),
 | 
				
			||||||
            ("Kmw", "°KMW"),
 | 
					            ("Buckets", "Flächenbindung", "|kg", 36),
 | 
				
			||||||
            ("Buckets", "Flächenbindung"),
 | 
					            ("Weight", "Gewicht", "kg", 16),
 | 
				
			||||||
            ("Weight", "Gewicht"),
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private readonly int MgNr;
 | 
					        private readonly int MgNr;
 | 
				
			||||||
@@ -71,11 +70,10 @@ namespace Elwig.Models.Dtos {
 | 
				
			|||||||
        public string Variant;
 | 
					        public string Variant;
 | 
				
			||||||
        public string? Attribute;
 | 
					        public string? Attribute;
 | 
				
			||||||
        public string QualityLevel;
 | 
					        public string QualityLevel;
 | 
				
			||||||
        public double Oe;
 | 
					        public (double Oe, double Kmw) Gradation;
 | 
				
			||||||
        public double Kmw;
 | 
					 | 
				
			||||||
        public string[] Modifiers;
 | 
					        public string[] Modifiers;
 | 
				
			||||||
        public int Weight;
 | 
					        public int Weight;
 | 
				
			||||||
        public (string, int)[] Buckets;
 | 
					        public (string Name, int Value)[] Buckets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DeliveryConfirmationRow(DeliveryPart p) {
 | 
					        public DeliveryConfirmationRow(DeliveryPart p) {
 | 
				
			||||||
            var d = p.Delivery;
 | 
					            var d = p.Delivery;
 | 
				
			||||||
@@ -84,8 +82,7 @@ namespace Elwig.Models.Dtos {
 | 
				
			|||||||
            Variant = p.Variant.Name;
 | 
					            Variant = p.Variant.Name;
 | 
				
			||||||
            Attribute = p.Attribute?.Name;
 | 
					            Attribute = p.Attribute?.Name;
 | 
				
			||||||
            QualityLevel = p.Quality.Name;
 | 
					            QualityLevel = p.Quality.Name;
 | 
				
			||||||
            Oe = p.Oe;
 | 
					            Gradation = (p.Oe, p.Kmw);
 | 
				
			||||||
            Kmw = p.Kmw;
 | 
					 | 
				
			||||||
            Modifiers = p.Modifiers
 | 
					            Modifiers = p.Modifiers
 | 
				
			||||||
                .Select(m => m.Name)
 | 
					                .Select(m => m.Name)
 | 
				
			||||||
                .ToArray();
 | 
					                .ToArray();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,18 +8,18 @@ using System.Threading.Tasks;
 | 
				
			|||||||
namespace Elwig.Models.Dtos {
 | 
					namespace Elwig.Models.Dtos {
 | 
				
			||||||
    public class MemberDeliveryPerVariantData : DataTable<MemberDeliveryPerVariantRow> {
 | 
					    public class MemberDeliveryPerVariantData : DataTable<MemberDeliveryPerVariantRow> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static readonly (string, string, int)[] FieldNames = new[] {
 | 
					        private static readonly (string, string, string?, int)[] FieldNames = new[] {
 | 
				
			||||||
            ("MgNr", "MgNr.", 12),
 | 
					            ("MgNr", "MgNr.", null, 12),
 | 
				
			||||||
            ("Name", "Name", 40),
 | 
					            ("Name", "Name", null, 40),
 | 
				
			||||||
            ("GivenName", "Vorname", 40),
 | 
					            ("GivenName", "Vorname", null, 40),
 | 
				
			||||||
            ("Address", "Adresse", 60),
 | 
					            ("Address", "Adresse", null, 60),
 | 
				
			||||||
            ("Plz", "PLZ", 10),
 | 
					            ("Plz", "PLZ", null, 10),
 | 
				
			||||||
            ("Locality", "Ort", 60),
 | 
					            ("Locality", "Ort", null, 60),
 | 
				
			||||||
            ("SortIds", "Sorte", 12),
 | 
					            ("SortIds", "Sorte", null, 12),
 | 
				
			||||||
            ("AttrIds", "Attribut", 16),
 | 
					            ("AttrIds", "Attribut", null, 16),
 | 
				
			||||||
            ("Weights", "Geliefert", 22),
 | 
					            ("Weights", "Geliefert", "kg", 22),
 | 
				
			||||||
            ("Areas", "Fläche", 22),
 | 
					            ("Areas", "Fläche", "m²", 22),
 | 
				
			||||||
            ("Yields", "Ertrag", 22),
 | 
					            ("Yields", "Ertrag", "kg/ha", 22),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,19 +7,19 @@ using System.Threading.Tasks;
 | 
				
			|||||||
namespace Elwig.Models.Dtos {
 | 
					namespace Elwig.Models.Dtos {
 | 
				
			||||||
    public class OverUnderDeliveryData : DataTable<OverUnderDeliveryRow> {
 | 
					    public class OverUnderDeliveryData : DataTable<OverUnderDeliveryRow> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static readonly (string, string, int)[] FieldNames = new[] {
 | 
					        private static readonly (string, string, string?, int)[] FieldNames = new[] {
 | 
				
			||||||
            ("MgNr", "MgNr.", 12),
 | 
					            ("MgNr", "MgNr.", null, 12),
 | 
				
			||||||
            ("Name", "Name", 40),
 | 
					            ("Name", "Name", null, 40),
 | 
				
			||||||
            ("GivenName", "Vorname", 40),
 | 
					            ("GivenName", "Vorname", null, 40),
 | 
				
			||||||
            ("Address", "Adresse", 60),
 | 
					            ("Address", "Adresse", null, 60),
 | 
				
			||||||
            ("Plz", "PLZ", 10),
 | 
					            ("Plz", "PLZ", null, 10),
 | 
				
			||||||
            ("Locality", "Ort", 60),
 | 
					            ("Locality", "Ort", null, 60),
 | 
				
			||||||
            ("BusinessShares", "GA", 10),
 | 
					            ("BusinessShares", "GA", null, 10),
 | 
				
			||||||
            ("DeliveryObligation", "Lieferpflicht", 22),
 | 
					            ("DeliveryObligation", "Lieferpflicht", "kg", 22),
 | 
				
			||||||
            ("DeliveryRight", "Lieferrecht", 22),
 | 
					            ("DeliveryRight", "Lieferrecht", "kg", 22),
 | 
				
			||||||
            ("Weight", "Geliefert", 22),
 | 
					            ("Weight", "Geliefert", "kg", 22),
 | 
				
			||||||
            ("OverUnderDelivery", "Über-/Unterliefert", 35),
 | 
					            ("OverUnderDelivery", "Über-/Unterliefert", "kg", 35),
 | 
				
			||||||
            ("Percent", "Prozent", 16),
 | 
					            ("Percent", "Prozent", "%", 16),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public OverUnderDeliveryData(IEnumerable<OverUnderDeliveryRow> rows, int year) :
 | 
					        public OverUnderDeliveryData(IEnumerable<OverUnderDeliveryRow> rows, int year) :
 | 
				
			||||||
@@ -75,7 +75,7 @@ namespace Elwig.Models.Dtos {
 | 
				
			|||||||
            Weight > DeliveryRight ? Weight - DeliveryRight : null;
 | 
					            Weight > DeliveryRight ? Weight - DeliveryRight : null;
 | 
				
			||||||
        [NotMapped]
 | 
					        [NotMapped]
 | 
				
			||||||
        public double? Percent =>
 | 
					        public double? Percent =>
 | 
				
			||||||
            Weight < DeliveryObligation ? Math.Round(Weight * 100.0 / DeliveryObligation - 100.0, 1) :
 | 
					            Weight < DeliveryObligation ? Weight * 100.0 / DeliveryObligation - 100.0 :
 | 
				
			||||||
            Weight > DeliveryRight ? Math.Round(Weight * 100.0 / DeliveryRight - 100, 1) : null;
 | 
					            Weight > DeliveryRight ? Weight * 100.0 / DeliveryRight - 100 : null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user