diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index d75c235e1..a2e30e4a0 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -22,6 +22,6 @@
"open-southeners.laravel-pint",
"damianbal.vs-phpclassgen",
"bmewburn.vscode-intelephense-client",
- "vue.volar"
+ "octref.vetur"
]
}
diff --git a/Changelog.md b/Changelog.md
index 7bc74a91c..15c5c05c8 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,5 +1,9 @@
# Changelog
+## 5.8.0
+
+* Consolidated donor/donation export dialogs into separate page, with more options, and improved performance of Excel export
+
## 5.7.0
* Added option to select year for donors export
diff --git a/app/Exports/Fundraising/DonationsExport.php b/app/Exports/Fundraising/DonationsExport.php
index b1f6b9da2..d69227515 100644
--- a/app/Exports/Fundraising/DonationsExport.php
+++ b/app/Exports/Fundraising/DonationsExport.php
@@ -25,7 +25,7 @@ private function getDonationsQuery()
{
return $this->donor != null
? $this->donor->donations()
- : Donation::query();
+ : Donation::query()->with('donor');
}
public function sheets(): array
diff --git a/app/Exports/Fundraising/DonorsExport.php b/app/Exports/Fundraising/DonorsExport.php
index 3ff7e782e..e12c07d8a 100644
--- a/app/Exports/Fundraising/DonorsExport.php
+++ b/app/Exports/Fundraising/DonorsExport.php
@@ -25,7 +25,7 @@ class DonorsExport extends BaseExport implements FromQuery, WithColumnFormatting
*/
private array $years;
- public function __construct(?int $year = null)
+ public function __construct(?int $year = null, private bool $includeChannels = false, private bool $showAllDonors = true)
{
$this->orientation = PageOrientation::Landscape;
@@ -34,29 +34,41 @@ public function __construct(?int $year = null)
now()->year,
];
- $this->usedCurrenciesChannels = Donation::select('currency', 'channel')
- ->selectRaw('YEAR(date) as year')
- ->selectRaw('SUM(amount) as amount')
- ->having('amount', '>', 0)
- ->where(function (Builder $qry) {
- foreach ($this->years as $year) {
- $qry->orWhereYear('date', '=', $year);
- }
- })
- ->groupBy('currency')
- ->groupBy('channel')
- ->groupBy('year')
- ->orderBy('year')
- ->orderBy('currency')
- ->orderBy('channel')
- ->get();
+ if ($includeChannels) {
+ $this->usedCurrenciesChannels = Donation::select('currency', 'channel')
+ ->selectRaw('YEAR(date) as year')
+ ->selectRaw('SUM(amount) as amount')
+ ->having('amount', '>', 0)
+ ->where(function (Builder $qry) {
+ foreach ($this->years as $year) {
+ $qry->orWhereYear('date', '=', $year);
+ }
+ })
+ ->groupBy('currency')
+ ->groupBy('channel')
+ ->groupBy('year')
+ ->orderBy('year')
+ ->orderBy('currency')
+ ->orderBy('channel')
+ ->get();
+ }
}
public function query(): Builder
{
- return Donor::orderBy('first_name')
+ return Donor::query()
+ ->with(['comments', 'tags'])
+ ->orderBy('first_name')
->orderBy('last_name')
- ->orderBy('company');
+ ->orderBy('company')
+ ->when(! $this->showAllDonors, fn (Builder $q) => $q->whereHas('donations', function (Builder $query) {
+ $query->where(function (Builder $qry) {
+ foreach ($this->years as $year) {
+ $qry->orWhereYear('date', $year);
+ }
+ });
+ })
+ );
}
public function title(): string
@@ -86,8 +98,10 @@ public function headings(): array
foreach ($this->years as $year) {
$headings[] = __('Donations').' '.$year;
}
- foreach ($this->usedCurrenciesChannels as $cc) {
- $headings[] = $cc->currency.' via '.$cc->channel.' in '.$cc->year;
+ if ($this->includeChannels) {
+ foreach ($this->usedCurrenciesChannels as $cc) {
+ $headings[] = $cc->currency.' via '.$cc->channel.' in '.$cc->year;
+ }
}
}
@@ -119,12 +133,14 @@ public function map($donor): array
foreach ($this->years as $year) {
$map[] = $donor->amountPerYear($year) ?? 0;
}
- $amounts = $donor->amountByChannelCurrencyYear();
- foreach ($this->usedCurrenciesChannels as $cc) {
- $map[] = optional($amounts->where('year', $cc->year)
- ->where('currency', $cc->currency)
- ->where('channel', $cc->channel)
- ->first())->total ?? null;
+ if ($this->includeChannels) {
+ $amounts = $donor->amountByChannelCurrencyYear();
+ foreach ($this->usedCurrenciesChannels as $cc) {
+ $map[] = optional($amounts->where('year', $cc->year)
+ ->where('currency', $cc->currency)
+ ->where('channel', $cc->channel)
+ ->first())->total ?? null;
+ }
}
}
@@ -137,13 +153,17 @@ public function columnFormats(): array
if (Auth::user()->can('viewAny', Donation::class)) {
foreach ($this->years as $year) {
$formats['O'] = config('fundraising.base_currency_excel_format');
- $formats['P'] = config('fundraising.base_currency_excel_format');
+ if (count($this->years) == 2) {
+ $formats['P'] = config('fundraising.base_currency_excel_format');
+ }
}
- $i = Coordinate::columnIndexFromString(count($this->years) == 2 ? 'P' : 'O');
- foreach ($this->usedCurrenciesChannels as $cc) {
- $i++;
- $column = Coordinate::stringFromColumnIndex($i);
- $formats[$column] = config('fundraising.currencies_excel_format')[$cc->currency];
+ if ($this->includeChannels) {
+ $i = Coordinate::columnIndexFromString(count($this->years) == 2 ? 'P' : 'O');
+ foreach ($this->usedCurrenciesChannels as $cc) {
+ $i++;
+ $column = Coordinate::stringFromColumnIndex($i);
+ $formats[$column] = config('fundraising.currencies_excel_format')[$cc->currency];
+ }
}
}
diff --git a/app/Http/Controllers/Fundraising/API/DonationController.php b/app/Http/Controllers/Fundraising/API/DonationController.php
index cecd804f6..26df7aa82 100644
--- a/app/Http/Controllers/Fundraising/API/DonationController.php
+++ b/app/Http/Controllers/Fundraising/API/DonationController.php
@@ -188,17 +188,17 @@ public function export(Request $request): BinaryFileResponse
$extension = $request->input('format', 'xlsx');
+ $includeAddress = $request->boolean('includeAddress');
+ $year = $request->input('year', null);
+
$file_name = sprintf(
'%s - %s (%s).%s',
config('app.name'),
- __('Donations'),
- Carbon::now()->toDateString(),
+ __('Donations').($year !== null ? (' '.intval($year)) : ''),
+ __('as of :date', ['date' => Carbon::now()->isoFormat('LL')]),
$extension
);
- $includeAddress = $request->boolean('includeAddress');
- $year = $request->input('year', null);
-
return (new DonationsExport(includeAddress: $includeAddress, year: $year))->download($file_name);
}
diff --git a/app/Http/Controllers/Fundraising/API/DonorController.php b/app/Http/Controllers/Fundraising/API/DonorController.php
index 523727c2d..32a2b1564 100644
--- a/app/Http/Controllers/Fundraising/API/DonorController.php
+++ b/app/Http/Controllers/Fundraising/API/DonorController.php
@@ -195,22 +195,26 @@ public function export(Request $request): BinaryFileResponse
$request->validate([
'format' => Rule::in('xlsx'),
+ 'includeChannels' => 'boolean',
+ 'showAllDonors' => 'boolean',
'year' => ['integer', Rule::in(Donation::years())],
]);
$extension = $request->input('format', 'xlsx');
+ $year = $request->input('year', null);
+ $includeChannels = $request->boolean('includeChannels');
+ $showAllDonors = $request->boolean('showAllDonors');
+
$file_name = sprintf(
'%s - %s (%s).%s',
config('app.name'),
- __('Donors'),
- Carbon::now()->toDateString(),
+ __('Donors').($year !== null ? (' '.intval($year)) : ''),
+ __('as of :date', ['date' => Carbon::now()->isoFormat('LL')]),
$extension
);
- $year = $request->input('year', null);
-
- return (new DonorsExport($year))->download($file_name);
+ return (new DonorsExport(year: $year, includeChannels: $includeChannels, showAllDonors: $showAllDonors))->download($file_name);
}
public function budgets(Donor $donor): JsonResource
diff --git a/lang/de.json b/lang/de.json
index 2af3d0407..3fdf53f63 100644
--- a/lang/de.json
+++ b/lang/de.json
@@ -842,5 +842,9 @@
"Export donations": "Spenden exportieren",
"Include address of donor": "Inlusive Adressen der Spender",
"Export donors": "Spender exportieren",
- "Current and last year": "Dieses und letztes Jahr"
+ "Current and last year": "Dieses und letztes Jahr",
+ "as of :date": "Stand :date",
+ "Include channels and currencies": "Inklusive Kanälen und Währungen",
+ "Show donations of year": "Zeige Spenden vom Jahr",
+ "Include all donors which did not donate in the selected year": "Inklusive sämtlicher Spender welche im ausgewählten Jahr nichts gespendet haben"
}
diff --git a/resources/js/api/fundraising/donations.js b/resources/js/api/fundraising/donations.js
index a42e06a96..70ca4cc8e 100644
--- a/resources/js/api/fundraising/donations.js
+++ b/resources/js/api/fundraising/donations.js
@@ -37,6 +37,6 @@ export default {
},
async export(params) {
const url = route("api.fundraising.donations.export", params);
- return await api.get(url);
+ return await api.download(url);
},
}
diff --git a/resources/js/api/fundraising/donors.js b/resources/js/api/fundraising/donors.js
index 9f6743261..8b8308d4c 100644
--- a/resources/js/api/fundraising/donors.js
+++ b/resources/js/api/fundraising/donors.js
@@ -62,5 +62,9 @@ export default {
...params
});
return await api.get(url);
- }
+ },
+ async export(params) {
+ const url = route("api.fundraising.donors.export", params);
+ return await api.download(url);
+ },
}
diff --git a/resources/js/components/fundraising/DonationsExportDialog.vue b/resources/js/components/fundraising/DonationsExportDialog.vue
deleted file mode 100644
index d28fe196f..000000000
--- a/resources/js/components/fundraising/DonationsExportDialog.vue
+++ /dev/null
@@ -1,121 +0,0 @@
-
-
-