Finish send mail dialog, fixes #12

This commit is contained in:
2025-11-19 14:30:24 +01:00
parent d6e58a762c
commit ed017e0510
5 changed files with 57 additions and 31 deletions
+35 -2
View File
@@ -20,12 +20,17 @@
use App\Support\ApiDataTransformer; use App\Support\ApiDataTransformer;
use DateTime; use DateTime;
use tbQuar\Facades\Quar; use tbQuar\Facades\Quar;
use App\Mail\Reminder;
use Illuminate\Support\Facades\Mail;
class InvoiceController extends Controller class InvoiceController extends Controller
{ {
public function show() public function show()
{ {
return Inertia::render('Invoices', ['invoicesData' => $this->summaryThisYear()] return Inertia::render(
'Invoices',
['invoicesData' => $this->summaryThisYear()]
); );
} }
@@ -569,7 +574,7 @@ public function update(Request $request, $id)
} }
} }
public function delete(Request $request, $id) public function delete(Request $request, int $id)
{ {
DB::beginTransaction(); DB::beginTransaction();
@@ -591,6 +596,34 @@ public function delete(Request $request, $id)
} }
} }
public function remind(Request $request, int $id)
{
$invoice = InvoiceController::single($id);
$to = $request->query('to');
$cc = $request->query('cc');
// TODO: get from settings
$bcc = 'buchhaltung@tooloop.de';
if (empty($to) || !filter_var($to, FILTER_VALIDATE_EMAIL)) {
return response()->json([
'error' => 'Keine gültige E_Mail-Adresse ' . $to
], 400);
}
if (!empty($cc) && !filter_var($cc, FILTER_VALIDATE_EMAIL)) {
return response()->json([
'error' => 'Keine gültige E_Mail-Adresse ' . $cc
], 400);
}
Mail::to($to)
->cc($cc)
->bcc($cc)
->send(new Reminder($invoice));
// return new Reminder($invoice);
}
/** /**
* Generate the next available invoice number * Generate the next available invoice number
*/ */
-1
View File
@@ -28,7 +28,6 @@ public function envelope(): Envelope
return new Envelope( return new Envelope(
// TODO: get from settings // TODO: get from settings
from: new Address('buchhaltung@tooloop.de', 'Tooloop Multimedia'), from: new Address('buchhaltung@tooloop.de', 'Tooloop Multimedia'),
bcc: [new Address('daniel.stock@tooloop.de', 'Daniel Stock')],
subject: 'Zahlungserinnerung', subject: 'Zahlungserinnerung',
); );
} }
@@ -163,7 +163,6 @@ watch(invoice,
if (newValue.customerId && newValue.customerId !== 0) { if (newValue.customerId && newValue.customerId !== 0) {
// if (importCustomer.value != newValue.customer) // if (importCustomer.value != newValue.customer)
// console.warn('trigger importCustomer watcher') // console.warn('trigger importCustomer watcher')
console.log(newValue, newValue.customerId)
customers.value.find(customer => { customers.value.find(customer => {
if (customer.id === newValue.customerId) { if (customer.id === newValue.customerId) {
if (invoice.value) invoice.value.customer = customer as Customer if (invoice.value) invoice.value.customer = customer as Customer
@@ -413,8 +412,8 @@ const openReminderDialog = function () {
reminderDialogOpen.value = true reminderDialogOpen.value = true
} }
const sendReminder = async function (recipient: string | undefined) { const sendReminder = async function (to: string | undefined, cc: string | undefined) {
if (!recipient) return if (!to) return
if (!invoice.value || !invoice.value.id) return if (!invoice.value || !invoice.value.id) return
// Close dialog // Close dialog
@@ -425,8 +424,12 @@ const sendReminder = async function (recipient: string | undefined) {
try { try {
// await axios call // await axios call
await axios.get('/api/invoices/' + invoice.value.id + '/remind/' + recipient) let request = '/api/invoices/' + invoice.value.id + '/remind?to=' + to
toast.success("Zahlungserinnerung gesendet", { description: recipient }) if (cc) request += '&cc=' + cc
await axios.get(request)
invoice.value.paymentStatus = 'reminded'
save()
toast.success("Zahlungserinnerung gesendet", { description: to })
} catch (error: any) { } catch (error: any) {
toast.error(error?.title || 'Fehler', { description: error?.message || String(error) }) toast.error(error?.title || 'Fehler', { description: error?.message || String(error) })
} finally { } finally {
@@ -819,7 +822,7 @@ const updateLineItems = (newItems: LineItem[]) => {
</Dialog> </Dialog>
<SendMailDialog v-model:open="reminderDialogOpen" title="Zahlungserinnerung senden?" description="" <SendMailDialog v-model:open="reminderDialogOpen" title="Zahlungserinnerung senden?" description=""
:recipient="billingContactEmail" @send="(recipient: string | undefined) => sendReminder(recipient)" /> :to="billingContactEmail" @send="(to, cc) => sendReminder(to, cc)" />
</template> </template>
@@ -9,17 +9,19 @@ import { Label } from "@/components/ui/label"
const props = defineProps<DialogRootProps & { const props = defineProps<DialogRootProps & {
title: string, title: string,
description?: string, description?: string,
recipient?: string to?: string,
cc?: string
}>() }>()
const recipient = ref<string | undefined>(props.recipient) const to = ref<string | undefined>(props.to)
const cc = ref<string | undefined>(props.cc)
const emits = defineEmits<DialogRootEmits & { const emits = defineEmits<DialogRootEmits & {
send: [recipient: string | undefined] send: [to: string | undefined, cc: string | undefined]
}>() }>()
const forwarded = useForwardPropsEmits(props, emits) const forwarded = useForwardPropsEmits(props, emits)
watch(() => props.open, watch(() => props.open,
(newValue, oldValue) => { (newValue, oldValue) => {
recipient.value = props.recipient to.value = props.to
} }
) )
</script> </script>
@@ -32,15 +34,15 @@ watch(() => props.open,
<DialogDescription v-if="props.description" v-html="props.description" /> <DialogDescription v-if="props.description" v-html="props.description" />
</DialogHeader> </DialogHeader>
<div class="grid grid-cols-[min-content_1fr] gap-4 py-4"> <div class="grid grid-cols-[min-content_1fr] gap-4 py-4">
<Label for="email" class="text-right text-muted-foreground"> <Label for="to" class="text-right text-muted-foreground">
An An
</Label> </Label>
<Input id="email" required v-model="recipient" type="email" placeholder="E-Mail" /> <Input id="to" required v-model="to" type="email" placeholder="E-Mail" />
<Label for="email" class="text-right text-muted-foreground"> <Label for="cc" class="text-right text-muted-foreground">
Kopie Kopie
</Label> </Label>
<Input id="email" required :value="'buchhaltung@tooloop.de'" type="email" placeholder="E-Mail" /> <Input id="cc" v-model="cc" type="email" placeholder="E-Mail" />
</div> </div>
<DialogFooter> <DialogFooter>
<DialogClose as-child> <DialogClose as-child>
@@ -48,7 +50,7 @@ watch(() => props.open,
Abbrechen Abbrechen
</Button> </Button>
</DialogClose> </DialogClose>
<Button variant="destructive" @click="$emit('send', recipient)"> <Button variant="destructive" @click="$emit('send', to, cc)">
E-Mail senden E-Mail senden
</Button> </Button>
</DialogFooter> </DialogFooter>
+2 -13
View File
@@ -4,11 +4,9 @@
use App\Http\Controllers\CustomerController; use App\Http\Controllers\CustomerController;
use App\Http\Controllers\InvoiceController; use App\Http\Controllers\InvoiceController;
use App\Http\Controllers\LineItemController; use App\Http\Controllers\LineItemController;
use App\Mail\Reminder;
use App\Http\Controllers\PaymentTermsController; use App\Http\Controllers\PaymentTermsController;
use App\Http\Controllers\SettingController; use App\Http\Controllers\SettingController;
use App\Mail\OrderConfirmation; use App\Mail\OrderConfirmation;
use Illuminate\Support\Facades\Mail;
Route::get('/customers/{id}', [CustomerController::class, 'single']); Route::get('/customers/{id}', [CustomerController::class, 'single']);
@@ -26,21 +24,12 @@
Route::get('/invoices/{id}', [InvoiceController::class, 'single']); Route::get('/invoices/{id}', [InvoiceController::class, 'single']);
Route::put('/invoices/{id}', [InvoiceController::class, 'update']); Route::put('/invoices/{id}', [InvoiceController::class, 'update']);
Route::delete('/invoices/{id}', [InvoiceController::class, 'delete']); Route::delete('/invoices/{id}', [InvoiceController::class, 'delete']);
Route::get('/invoices/{id}/remind', [InvoiceController::class, 'remind']);
Route::get('/invoices/{id}/remind/{recipient}', function ($id, $recipient) {
if (empty($recipient) || !filter_var($recipient, FILTER_VALIDATE_EMAIL)) {
return response()->json([
'error' => 'Keine gültige E_Mail-Adresse'
], 400);
}
$invoice = InvoiceController::single($id);
Mail::to($recipient)->send(new Reminder($invoice));
// return new Reminder($invoice);
});
Route::get('/lineitems/{invoiceId}', [LineItemController::class, 'index']); Route::get('/lineitems/{invoiceId}', [LineItemController::class, 'index']);
Route::get('/offers/{id}/confirm', function ($id) { Route::get('/offers/{id}/confirm', function ($id) {
// $offer = offerController::single($id); // $offer = offerController::single($id);
$offer = [ $offer = [