Invoice PAIN & CSV can be uploaded
This commit is contained in:
110
app/Domains/CostUnit/Controllers/ExportController.php
Normal file
110
app/Domains/CostUnit/Controllers/ExportController.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\CostUnit\Controllers;
|
||||
|
||||
use App\Domains\Invoice\Actions\ChangeStatus\ChangeStatusCommand;
|
||||
use App\Domains\Invoice\Actions\ChangeStatus\ChangeStatusRequest;
|
||||
use App\Domains\Invoice\Actions\CreateInvoice\CreateInvoiceRequest;
|
||||
use App\Domains\Invoice\Actions\CreateInvoiceReceipt\CreateInvoiceReceiptCommand;
|
||||
use App\Domains\Invoice\Actions\CreateInvoiceReceipt\CreateInvoiceReceiptRequest;
|
||||
use App\Enumerations\InvoiceStatus;
|
||||
use App\Models\Tenant;
|
||||
use App\Providers\FileWriteProvider;
|
||||
use App\Providers\InvoiceCsvFileProvider;
|
||||
use App\Providers\PainFileProvider;
|
||||
use App\Providers\WebDavProvider;
|
||||
use App\Providers\ZipArchiveFileProvider;
|
||||
use App\Scopes\CommonController;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class ExportController extends CommonController {
|
||||
public function __invoke(int $costUnitId) {
|
||||
$costUnit = $this->costUnits->getById($costUnitId);
|
||||
|
||||
$invoicesForExport = $this->invoices->getByStatus($costUnit, InvoiceStatus::INVOICE_STATUS_APPROVED, false);
|
||||
|
||||
$webdavProvider = new WebDavProvider(WebDavProvider::INVOICE_PREFIX . $this->tenant->url . '/' . $costUnit->name);
|
||||
|
||||
$painFileData = $this->painData($invoicesForExport);
|
||||
$csvData = $this->csvData($invoicesForExport);
|
||||
|
||||
$filePrefix = Tenant::getTempDirectory();
|
||||
|
||||
$painFileWriteProvider = new FileWriteProvider($filePrefix . 'abrechnungen-' . date('Y-m-d_H-i') . '-sepa.xml', $painFileData);
|
||||
$painFileWriteProvider->writeToFile();
|
||||
|
||||
$csvFileWriteProvider = new FileWriteProvider($filePrefix . 'abrechnungen-' . date('Y-m-d_H-i') . '.csv', $csvData);
|
||||
$csvFileWriteProvider->writeToFile();
|
||||
|
||||
if ($this->tenant->upload_exports) {
|
||||
$webdavProvider->uploadFile($painFileWriteProvider->fileName);
|
||||
$webdavProvider->uploadFile($csvFileWriteProvider->fileName);
|
||||
}
|
||||
|
||||
$downloadZipArchiveFiles = [
|
||||
$painFileWriteProvider->fileName,
|
||||
$csvFileWriteProvider->fileName
|
||||
];
|
||||
|
||||
foreach ($invoicesForExport as $invoice) {
|
||||
$changeStatusRequest = new ChangeStatusRequest($invoice, InvoiceStatus::INVOICE_STATUS_EXPORTED);
|
||||
$changeStatusCommand = new ChangeStatusCommand($changeStatusRequest);
|
||||
$changeStatusCommand->execute();
|
||||
|
||||
if ($this->tenant->download_exports) {
|
||||
$createInvoiceReceiptRequest = new CreateInvoiceReceiptRequest($invoice);
|
||||
$createInvoiceReceiptCommand = new CreateInvoiceReceiptCommand($createInvoiceReceiptRequest);
|
||||
$response = $createInvoiceReceiptCommand->execute();
|
||||
|
||||
$downloadZipArchiveFiles[] = $response->fileName;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->tenant->download_exports) {
|
||||
$zipFile = Tenant::getTempDirectory() . 'Abrechnungen-' . $costUnit->name . '.zip';
|
||||
$zipFileProvider = new ZipArchiveFileProvider($zipFile);
|
||||
foreach ($downloadZipArchiveFiles as $file) {
|
||||
$zipFileProvider->addFile($file);
|
||||
}
|
||||
|
||||
$zipFileProvider->create();
|
||||
foreach ($downloadZipArchiveFiles as $file) {
|
||||
Storage::delete($file);
|
||||
}
|
||||
|
||||
Storage::delete($painFileWriteProvider->fileName);
|
||||
Storage::delete($csvFileWriteProvider->fileName);
|
||||
|
||||
return response()->download(
|
||||
storage_path('app/private/' . $zipFile),
|
||||
basename($zipFile),
|
||||
['Content-Type' => 'application/zip']
|
||||
);
|
||||
}
|
||||
|
||||
Storage::delete($painFileWriteProvider->fileName);
|
||||
Storage::delete($csvFileWriteProvider->fileName);
|
||||
return response()->json([
|
||||
'message' => 'Die Abrechnungen wurden exportiert.' . PHP_EOL .'Die Belege werden asynchron auf dem Webdav-Server hinterlegt.' . PHP_EOL . PHP_EOL . 'Sollten diese in 15 Minuten nicht vollständig sein, kontaktiere den Adminbistrator.'
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
private function painData(array $invoices) : string {
|
||||
$invoicesForPainFile = [];
|
||||
foreach ($invoices as $invoice) {
|
||||
if ($invoice->contact_bank_owner !== null && $invoice->contact_bank_iban !== '' && !$invoice->donation) {
|
||||
$invoicesForPainFile[] = $invoice;
|
||||
}
|
||||
}
|
||||
|
||||
$painFileProvider = new PainFileProvider($this->tenant->account_iban, $this->tenant->account_name, $this->tenant->account_bic, $invoicesForPainFile);
|
||||
return $painFileProvider->createPainFileContent();
|
||||
}
|
||||
|
||||
public function csvData(array $invoices) : string {
|
||||
$csvDateProvider = new InvoiceCsvFileProvider($invoices);
|
||||
return $csvDateProvider->createCsvFileContent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ use App\Domains\CostUnit\Controllers\ChangeStateController;
|
||||
use App\Domains\CostUnit\Controllers\CreateController;
|
||||
use App\Domains\CostUnit\Controllers\DistanceAllowanceController;
|
||||
use App\Domains\CostUnit\Controllers\EditController;
|
||||
use App\Domains\CostUnit\Controllers\ExportController;
|
||||
use App\Domains\CostUnit\Controllers\ListController;
|
||||
use App\Domains\CostUnit\Controllers\OpenController;
|
||||
use App\Domains\CostUnit\Controllers\TreasurersEditController;
|
||||
@@ -37,6 +38,7 @@ Route::prefix('api/v1')
|
||||
Route::get('/treasurers', TreasurersEditController::class);
|
||||
Route::post('/treasurers', [TreasurersEditController::class, 'update']);
|
||||
|
||||
Route::get('/export-payouts', ExportController::class);
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
<script setup>
|
||||
import {createApp, ref} from 'vue'
|
||||
/*import {
|
||||
_mareike_download_as_zip,
|
||||
|
||||
_mareike_use_webdav
|
||||
} from "../../../assets/javascripts/library";*/
|
||||
//import LoadingModal from "../../../assets/components/LoadingModal.vue";
|
||||
//import Invoices from '../invoices/index.vue'
|
||||
import LoadingModal from "../../../../Views/Components/LoadingModal.vue";
|
||||
import { useAjax } from "../../../../../resources/js/components/ajaxHandler.js";
|
||||
import CostUnitDetails from "./CostUnitDetails.vue";
|
||||
import {toast} from "vue3-toastify";
|
||||
import Treasurers from "./Treasurers.vue";
|
||||
|
||||
//import CostUnitDetails from "./CostUnitDetails.vue";
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: [Array, Object],
|
||||
@@ -42,13 +34,8 @@ const show_cost_unit = ref(false)
|
||||
const showTreasurers = ref(false)
|
||||
const costUnit = ref(null)
|
||||
|
||||
|
||||
const { data, loading, error, request, download } = useAjax()
|
||||
|
||||
if (props.deep_jump_id > 0) {
|
||||
// open_invoice_list(props.deep_jump_id, 'new', props.deep_jump_id_sub)
|
||||
}
|
||||
|
||||
async function costUnitDetails(costUnitId) {
|
||||
const data = await request('/api/v1/cost-unit/' + costUnitId + '/details', {
|
||||
method: "GET",
|
||||
@@ -114,45 +101,50 @@ async function changeCostUnitState(costUnitId, endPoint) {
|
||||
}
|
||||
|
||||
|
||||
async function export_payouts(cost_unit_id) {
|
||||
showLoading.value = true;
|
||||
async function exportPayouts(costUnitId) {
|
||||
showLoading.value = true;
|
||||
|
||||
try {
|
||||
if (_mareike_download_as_zip()) {
|
||||
const response = await fetch("/wp-json/mareike/costunits/export-payouts", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
mareike_nonce: _mareike_nonce(),
|
||||
costunit: cost_unit_id,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error('Fehler beim Export (ZIP)');
|
||||
const blob = await response.blob();
|
||||
const downloadUrl = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = downloadUrl;
|
||||
a.download = `payouts-${cost_unit_id}.zip`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
window.URL.revokeObjectURL(downloadUrl);
|
||||
} else {
|
||||
await request("/wp-json/mareike/costunits/export-payouts", {
|
||||
method: "POST",
|
||||
body: {
|
||||
mareike_nonce: _mareike_nonce(),
|
||||
costunit: cost_unit_id,
|
||||
const response = await fetch('/api/v1/core/retrieve-global-data');
|
||||
const data = await response.json();
|
||||
const exportUrl = '/api/v1/cost-unit/' + costUnitId + '/export-payouts';
|
||||
|
||||
try {
|
||||
if (data.tenant.download_exports) {
|
||||
const response = await fetch(exportUrl, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error('Fehler beim Export (ZIP)');
|
||||
|
||||
const blob = await response.blob();
|
||||
const downloadUrl = window.URL.createObjectURL(blob);
|
||||
console.log(response.headers.get("content-type"));
|
||||
const a = document.createElement("a");
|
||||
a.style.display = "none";
|
||||
a.href = downloadUrl;
|
||||
a.download = "Abrechnungen-Sippenstunden.zip";
|
||||
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
|
||||
setTimeout(() => {
|
||||
window.URL.revokeObjectURL(downloadUrl);
|
||||
document.body.removeChild(a);
|
||||
}, 100);
|
||||
} else {
|
||||
const response = await request(exportUrl, {
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
toast.success(response.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
showLoading.value = false;
|
||||
toast.success('Die Abrechnungen wurden exportiert.');
|
||||
} catch (err) {
|
||||
showLoading.value = false;
|
||||
toast.error('Beim Export der Abrechnungen ist ein Fehler aufgetreten.');
|
||||
}
|
||||
showLoading.value = false;
|
||||
|
||||
} catch (err) {
|
||||
showLoading.value = false;
|
||||
toast.error('Beim Export der Abrechnungen ist ein Fehler aufgetreten.');
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -176,7 +168,7 @@ async function export_payouts(cost_unit_id) {
|
||||
<input v-if="!costUnit.archived" type="button" value="Abrechnungen bearbeiten" @click="loadInvoices(costUnit.id)" />
|
||||
<input v-else type="button" value="Abrechnungen einsehen" />
|
||||
<br />
|
||||
<input v-if="!costUnit.archived" type="button" value="Genehmigte Abrechnungen exportieren" style="margin-top: 10px;" />
|
||||
<input v-if="!costUnit.archived" type="button" @click="exportPayouts(costUnit.id)" value="Genehmigte Abrechnungen exportieren" style="margin-top: 10px;" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -217,17 +209,10 @@ async function export_payouts(cost_unit_id) {
|
||||
<Treasurers :data="costUnit" :showTreasurers="showTreasurers" v-if="showTreasurers" @closeTreasurers="showTreasurers = false" />
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div v-else-if="showInvoiceList">
|
||||
<div v-else-if="showInvoiceList">
|
||||
<invoices :data="invoices" :load_invoice_id="props.deep_jump_id_sub" :cost_unit_id="current_cost_unit" />
|
||||
|
||||
|
||||
<LoadingModal :show="showLoading" v-if="_mareike_use_webdav()" message="Die PDF-Dateien werden asynchron erzeugt, diese sollten in 10 Minuten auf dem Webdav-Server liegen', 'mareike')" />
|
||||
<LoadingModal :show="showLoading" v-else message='Die Abrechnungen werden exportiert, bitte warten.' />
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
@@ -236,7 +221,7 @@ async function export_payouts(cost_unit_id) {
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
|
||||
<LoadingModal :show="showLoading" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user