add receipt to payments

shift-build-2464
Nadim Salloum 2021-10-20 16:59:21 +02:00
parent 6cd67a5280
commit f2d38aa3c7
9 changed files with 197 additions and 14 deletions

View File

@ -267,6 +267,7 @@ class ContractController extends Controller
'date' => $payment->date,
'amount' => $payment->amount->format(),
'type' => $payment->type,
'print_link' => $payment->print_link,
'delete_link' => $payment->delete_link,
];
}),

View File

@ -6,6 +6,7 @@ use Carbon\Carbon;
use Inertia\Inertia;
use App\Models\Payment;
use App\Models\Contract;
use Barryvdh\DomPDF\Facade as PDF;
use App\Enums\PaymentType;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
@ -41,6 +42,20 @@ class PaymentController extends Controller
return Redirect::route('contracts.show', $payment->contract);
}
public function print(Contract $contract, Payment $payment)
{
$contxt = stream_context_create([
'ssl' => [
'verify_peer' => FALSE,
'verify_peer_name' => FALSE,
'allow_self_signed'=> TRUE
]
]);
$pdf = PDF::setOptions(['isHtml5ParserEnabled' => true, 'isRemoteEnabled' => true])->loadView('receipt', compact('contract', 'payment'));
$pdf->getDomPDF()->setHttpContext($contxt);
return $pdf->stream($payment->date . '_quittung.pdf');
}
public function destroy(Request $request, Contract $contract)
{
if (Payment::destroy((int)$request->get('id'))) {

View File

@ -65,6 +65,11 @@ class Payment extends Model
};
}
public function getPrintLinkAttribute()
{
return route('payments.print', [$this->contract->id, $this->id]);
}
public function getDeleteLinkAttribute()
{
return route('payments.destroy', [$this->contract->id, $this->id]);

View File

@ -4,6 +4,7 @@ namespace App\Providers;
use App\Models\Car;
use App\Models\Contact;
use App\Models\Payment;
use App\Models\Contract;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
@ -56,12 +57,16 @@ class RouteServiceProvider extends ServiceProvider
});
Route::bind('contract', function ($value) {
if (in_array(Route::currentRouteName(), ['contracts.show', 'contracts.restore', 'payments.destroy'])) {
if (in_array(Route::currentRouteName(), ['contracts.show', 'contracts.restore', 'payments.destroy', 'payments.print'])) {
return Contract::withTrashed()->find($value);
}
return Contract::find($value);
});
Route::bind('payment', function ($value) {
return \App\Models\Payment::find($value);
});
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)

44
public/js/app.js vendored
View File

@ -20493,6 +20493,10 @@ __webpack_require__.r(__webpack_exports__);
key: 'type',
value: 'Bezahlart',
sortable: false
}, {
key: 'print',
value: 'Quittung',
sortable: false
}, {
key: 'delete',
value: '',
@ -26153,26 +26157,27 @@ var _hoisted_13 = {
"class": "flex items-center"
};
var _hoisted_14 = ["onClick"];
var _hoisted_15 = {
key: 2,
var _hoisted_15 = ["href"];
var _hoisted_16 = {
key: 3,
"class": "2xl:px-5 lg:px-3 px-2 2xl:py-4 lg:py-3 py-2 flex items-center"
};
var _hoisted_16 = {
var _hoisted_17 = {
key: 0,
"class": "border-t w-px"
};
var _hoisted_17 = {
var _hoisted_18 = {
key: 0
};
var _hoisted_18 = ["colspan"];
var _hoisted_19 = {
var _hoisted_19 = ["colspan"];
var _hoisted_20 = {
key: 3
};
var _hoisted_20 = {
var _hoisted_21 = {
"class": "inline-flex font-medium text-gray-500 ml-3"
};
var _hoisted_21 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" Keine Einträge gefunden ");
var _hoisted_22 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" Keine Einträge gefunden ");
function render(_ctx, _cache, $props, $setup, $data, $options) {
var _this = this;
@ -26294,12 +26299,25 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
name: "trash-alt"
})], 8
/* PROPS */
, _hoisted_14)) : ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("span", _hoisted_15, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($options.resolve(col.key, row)), 1
, _hoisted_14)) : col.key == 'print' ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("a", {
key: 2,
"class": "2xl:px-5 lg:px-3 px-2 2xl:py-4 lg:py-3 py-2 flex items-center",
target: "_blank",
href: row.print_link
}, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_unicon, {
fill: "#b2b7ff",
"hover-fill": "indigo",
height: "24",
width: "24",
name: "file-download"
})], 8
/* PROPS */
, _hoisted_15)) : ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("span", _hoisted_16, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($options.resolve(col.key, row)), 1
/* TEXT */
))]);
}), 128
/* KEYED_FRAGMENT */
)), row.link && !$props.hideArrow ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("td", _hoisted_16, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_inertia_link, {
)), row.link && !$props.hideArrow ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("td", _hoisted_17, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_inertia_link, {
"class": "xl:pr-4 pr-2 xl:py-4 py-2 flex items-center",
href: row.link,
tabindex: "-1"
@ -26319,18 +26337,18 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
, ["href"])])) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)("v-if", true)]);
}), 128
/* KEYED_FRAGMENT */
)), $props.data.total === 0 ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("tr", _hoisted_17, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("td", {
)), $props.data.total === 0 ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("tr", _hoisted_18, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("td", {
"class": "border-t px-6 py-4",
colspan: $props.columns.length
}, "Keine Einträge gefunden", 8
/* PROPS */
, _hoisted_18)])) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)("v-if", true)])])) : ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_19, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", _hoisted_20, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_unicon, {
, _hoisted_19)])) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)("v-if", true)])])) : ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_20, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", _hoisted_21, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_unicon, {
fill: "#7e8491",
"class": "mr-2",
height: "24",
width: "24",
name: "meh"
}), _hoisted_21])])), $props.data.links ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createBlock)(_component_Paginator, {
}), _hoisted_22])])), $props.data.links ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createBlock)(_component_Paginator, {
key: 4,
"class": "mt-6",
links: $props.data.links

View File

@ -24,6 +24,7 @@ export default {
{ key: 'date', value: 'Datum', sortable: false },
{ key: 'amount', value: 'Betrag', sortable: false },
{ key: 'type', value: 'Bezahlart', sortable: false },
{ key: 'print', value: 'Quittung', sortable: false },
{ key: 'delete', value: '', sortable: false },
],
};

View File

@ -38,6 +38,9 @@
<span v-else-if="col.key == 'delete'" class="p-3 cursor-pointer" @click="this.$emit('delete', row.id)">
<unicon fill="#f04040" hover-fill="red" height="24" width="24" name="trash-alt"></unicon>
</span>
<a v-else-if="col.key == 'print'" class="2xl:px-5 lg:px-3 px-2 2xl:py-4 lg:py-3 py-2 flex items-center" target="_blank" :href="row.print_link">
<unicon fill="#b2b7ff" hover-fill="indigo" height="24" width="24" name="file-download"></unicon>
</a>
<span v-else class="2xl:px-5 lg:px-3 px-2 2xl:py-4 lg:py-3 py-2 flex items-center">
{{ resolve(col.key, row) }}
</span>

View File

@ -0,0 +1,134 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>
Quittung - {{ $contract->car->name }} - {{ $contract->contact->full_title }}
</title>
<style type="text/css">
* {
font-family: Verdana, Arial, sans-serif;
}
body {
margin: 0;
}
table{
font-size: x-small;
}
table tr td {
padding: 1px 0;
font-size: 12px;
}
.footnote {
padding: 5px 0;
margin: 25px 0 5px 0;
font-size: 9px;
border-top: 1px solid black;
border-bottom: 1px solid black;
}
tfoot tr td{
font-weight: bold;
font-size: x-small;
}
.gray {
background-color: lightgray
}
</style>
</head>
<body>
<table width="100%">
<tr>
<td align="left">
<pre>
<b>Your SwissCar GmbH</b>
Bernstrasse 27
8952 Schlieren
Tel: 079 680 34 44
E-Mail: info@yourswisscar.com
MwSt-Nr: CHE-226.272.050
</pre>
</td>
<td valign="top" alt="logo" width="100%" align="right"><x-logo /></td>
</tr>
</table>
<table width="100%">
<tr>
<td><h1>
Quittung
</h1></td>
</tr>
</table>
<table width="100%">
<tr>
<td width="15%"><b>Verkäufer</b></td>
<td width="35%">Your SwissCar GmbH</td>
<td width="15%"><b>Käufer</b></td>
<td width="35%">{{ $contract->contact->full_title }}</td>
</tr>
<tr>
<td>Strasse</td>
<td>Bernstrasse 27</td>
<td>Strasse</td>
<td>{{ $contract->contact->address }}</td>
</tr>
<tr>
<td>PLZ / Ort</td>
<td>8952 Schlieren</td>
<td>PLZ / Ort</td>
<td>{{ $contract->contact->full_city }}</td>
</tr>
<tr>
<td>Telefon</td>
<td>079 680 34 44</td>
<td>Telefon</td>
<td>{{ $contract->contact->phone }}</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>E-Mail</td>
<td>{{ $contract->contact->email }}</td>
</tr>
<tr><td>&nbsp;</td></tr>
</table>
<table width="100%">
<tr><td>Fahrzeug:</td></tr>
<tr>
<td><b>{{ $contract->car->name_with_year }}</b>, Stammnr.: {{ $contract->car->stammnummer }}</td>
</tr>
<tr><td>&nbsp;</td></tr>
<tr>
<td>Hiermit wird die folgende Einzahlung für das oben genannte Fahrzeug bestätigt:</td>
</tr>
</table>
<table width="100%">
<tr>
<td width="20%">Datum</td>
<td>{{ $payment->date }}</td>
</tr>
<tr>
<td>Zahlungsart</td>
<td>{{ $payment->type }}</td>
</tr>
<tr>
<td>Betrag</td>
<td><h4>{{ $payment->amount->format() }}</h4></td>
</tr>
<tr><td>&nbsp;</td></tr>
<tr><td>&nbsp;</td></tr>
<tr><td>&nbsp;</td></tr>
</p>
<table width="100%">
<tr>
<td>Ort, Datum</td>
</tr>
<tr><td>&nbsp;</td></tr>
<tr>
<td>Schlieren, {{ $payment->date }}</td>
</tr>
</table>
</body>
</html>

View File

@ -72,6 +72,7 @@ Route::middleware(['auth:sanctum', 'verified'])->group(function () {
Route::get('create', [PaymentController::class, 'create'])->name('payments.create');
Route::delete('delete', [PaymentController::class, 'destroy'])->name('payments.destroy');
Route::post('/', [PaymentController::class, 'store'])->name('payments.store');
Route::get('{payment}/print', [PaymentController::class, 'print'])->name('payments.print');
});
});