added stuff to manualinvoice
This commit is contained in:
@@ -208,8 +208,6 @@ class ManualInvoiceController extends TTCrud
|
||||
$post = json_decode(file_get_contents('php://input'), true);
|
||||
$id = $post['id'] ?? null;
|
||||
$recipientEmail = $post['email'] ?? null;
|
||||
$subject = $post['subject'] ?? 'Ihre Rechnung von XINON GmbH';
|
||||
$bodyText = $post['body'] ?? 'Sehr geehrte Damen und Herren,\n\nanbei erhalten Sie Ihre Rechnung.\n\nMit freundlichen Grüßen\nIhr Xinon Team';
|
||||
|
||||
if (!$id || !$recipientEmail) {
|
||||
self::returnJson(['success' => false, 'message' => 'ID oder E-Mail-Adresse fehlt']);
|
||||
@@ -222,6 +220,19 @@ class ManualInvoiceController extends TTCrud
|
||||
return;
|
||||
}
|
||||
|
||||
// Format invoice date for display
|
||||
$invoiceDateFormatted = date('d.m.Y', $invoice->invoice_date);
|
||||
|
||||
// Set default subject and body with invoice number and date
|
||||
$defaultSubject = "Ihre Rechnung {$invoice->invoice_number} vom {$invoiceDateFormatted}";
|
||||
$defaultBody = "Sehr geehrte Damen und Herren,\n\nanbei erhalten Sie Ihre Rechnung Nr. {$invoice->invoice_number} vom {$invoiceDateFormatted}.\n\nMit freundlichen Grüßen\nIhr XINON Team";
|
||||
|
||||
$subject = $post['subject'] ?? $defaultSubject;
|
||||
$bodyText = $post['body'] ?? $defaultBody;
|
||||
|
||||
// Convert literal \n strings to actual newlines (in case frontend sends escaped strings)
|
||||
$bodyText = str_replace('\n', "\n", $bodyText);
|
||||
|
||||
// Generate PDF
|
||||
$pdf_filename = $this->createPDFAction(true);
|
||||
if (!$pdf_filename || !file_exists($pdf_filename)) {
|
||||
@@ -232,19 +243,33 @@ class ManualInvoiceController extends TTCrud
|
||||
$pdfContent = file_get_contents($pdf_filename);
|
||||
|
||||
// --- HTML Email Generation ---
|
||||
$logoToolPath = BASEDIR . '/public/assets/images/the-tool-logo.png';
|
||||
$logoXinonPath = BASEDIR . '/public/assets/images/xinon-full.png';
|
||||
$logoToolExists = file_exists($logoToolPath);
|
||||
$logoXinonExists = file_exists($logoXinonPath);
|
||||
|
||||
// Construct HTML Body
|
||||
$html = '<!DOCTYPE html><html lang="de"><head><meta charset="UTF-8"><title>Rechnung</title><style>body { font-family: Arial, sans-serif; color: #333; }</style></head><body style="margin:0;padding:20px;background-color:#f3f4f6;">';
|
||||
$html .= '<div style="background-color:#fff;padding:20px;border-radius:8px;max-width:600px;margin:0 auto;box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);">';
|
||||
// Construct HTML Body with Outlook compatibility
|
||||
$html = '<!DOCTYPE html>';
|
||||
$html .= '<html lang="de" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">';
|
||||
$html .= '<head>';
|
||||
$html .= '<meta charset="UTF-8">';
|
||||
$html .= '<meta http-equiv="X-UA-Compatible" content="IE=edge">';
|
||||
$html .= '<meta name="viewport" content="width=device-width, initial-scale=1.0">';
|
||||
$html .= '<title>Rechnung</title>';
|
||||
$html .= '<!--[if mso]><xml><o:OfficeDocumentSettings><o:PixelsPerInch>96</o:PixelsPerInch></o:OfficeDocumentSettings></xml><![endif]-->';
|
||||
$html .= '<style>body { font-family: Arial, sans-serif; color: #333; margin: 0; padding: 0; }</style>';
|
||||
$html .= '</head>';
|
||||
$html .= '<body style="margin:0;padding:20px;background-color:#f3f4f6;">';
|
||||
|
||||
// Logos
|
||||
$html .= '<div style="text-align:center;margin-bottom:20px;border-bottom: 1px solid #e5e7eb;padding-bottom: 15px;">';
|
||||
if ($logoToolExists) $html .= '<img src="cid:logo_thetool" alt="The Tool" style="height:40px;margin-right:15px;vertical-align:middle;">';
|
||||
if ($logoXinonExists) $html .= '<img src="cid:logo_xinon" alt="Xinon" style="height:40px;vertical-align:middle;">';
|
||||
// Outlook-safe container table
|
||||
$html .= '<!--[if mso]><table role="presentation" width="600" cellspacing="0" cellpadding="0" border="0" align="center"><tr><td><![endif]-->';
|
||||
$html .= '<div style="background-color:#fff;padding:20px;border-radius:8px;max-width:600px;margin:0 auto;">';
|
||||
|
||||
// Logo with Outlook-safe sizing
|
||||
$html .= '<div style="text-align:center;margin-bottom:20px;border-bottom:1px solid #e5e7eb;padding-bottom:15px;">';
|
||||
if ($logoXinonExists) {
|
||||
$html .= '<!--[if mso]><table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0"><tr><td align="center"><![endif]-->';
|
||||
$html .= '<img src="cid:logo_xinon" alt="XINON GmbH" width="150" height="50" style="display:block;width:150px;height:50px;max-width:150px;margin:0 auto;">';
|
||||
$html .= '<!--[if mso]></td></tr></table><![endif]-->';
|
||||
}
|
||||
$html .= '</div>';
|
||||
|
||||
$html .= '<h2 style="color:#00558c;text-align:center;font-size:20px;margin-bottom:20px;">' . htmlspecialchars($subject) . '</h2>';
|
||||
@@ -254,7 +279,9 @@ class ManualInvoiceController extends TTCrud
|
||||
|
||||
$html .= '<br><div style="border-top:1px solid #eee;padding-top:20px;font-size:12px;color:#999;text-align:center;">';
|
||||
$html .= 'XINON GmbH | <a href="https://www.xinon.at" style="color:#00558c;text-decoration:none;">www.xinon.at</a>';
|
||||
$html .= '</div></div></body></html>';
|
||||
$html .= '</div></div>';
|
||||
$html .= '<!--[if mso]></td></tr></table><![endif]-->';
|
||||
$html .= '</body></html>';
|
||||
|
||||
$mail = new PHPMailer(true);
|
||||
try {
|
||||
@@ -269,12 +296,11 @@ class ManualInvoiceController extends TTCrud
|
||||
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
|
||||
$mail->Port = 587;
|
||||
|
||||
// Logos
|
||||
if ($logoToolExists) $mail->addEmbeddedImage($logoToolPath, 'logo_thetool');
|
||||
// Logo embedding
|
||||
if ($logoXinonExists) $mail->addEmbeddedImage($logoXinonPath, 'logo_xinon');
|
||||
|
||||
$mail->addReplyTo('backoffice@xinon.at', 'XINON Backoffice');
|
||||
$mail->setFrom('thetool@xinon.at', 'XINON TheTool');
|
||||
$mail->setFrom('thetool@xinon.at', 'XINON GmbH - Rechnungswesen');
|
||||
|
||||
$customerName = trim(($invoice->company ?: '') . ' ' . $invoice->firstname . ' ' . $invoice->lastname);
|
||||
$mail->addAddress($recipientEmail, $customerName);
|
||||
@@ -283,7 +309,10 @@ class ManualInvoiceController extends TTCrud
|
||||
$mail->Body = $html;
|
||||
$mail->AltBody = strip_tags($bodyText);
|
||||
|
||||
$mail->addStringAttachment($pdfContent, $invoice->invoice_number . '_Rechnung.pdf', 'base64', 'application/pdf');
|
||||
// Attachment filename: YYYY-MM-DD_InvoiceNumber_Rechnung.pdf
|
||||
$invoiceDateFile = date('Y-m-d', $invoice->invoice_date);
|
||||
$attachmentFilename = "{$invoiceDateFile}_{$invoice->invoice_number}_Rechnung.pdf";
|
||||
$mail->addStringAttachment($pdfContent, $attachmentFilename, 'base64', 'application/pdf');
|
||||
|
||||
$mail->send();
|
||||
|
||||
@@ -349,20 +378,21 @@ class ManualInvoiceController extends TTCrud
|
||||
$data['invoice_date'] = strtotime($data['invoice_date']);
|
||||
}
|
||||
|
||||
$data = array_merge([
|
||||
'invoice_number' => ManualInvoiceModel::getNextInvoiceNumber(),
|
||||
'invoice_date' => $data['invoice_date'] ?? time(),
|
||||
'status' => 'erstellt',
|
||||
'fibu_payment_skonto' => 0,
|
||||
'fibu_payment_skonto_rate' => 0,
|
||||
'gesamtrabatt' => 0,
|
||||
'total' => 0,
|
||||
'total_gross' => 0,
|
||||
'create_by' => $me->id,
|
||||
'edit_by' => $me->id,
|
||||
'create' => time(),
|
||||
'edit' => time()
|
||||
], $data);
|
||||
// Always generate invoice number (override any null from frontend)
|
||||
$data['invoice_number'] = ManualInvoiceModel::getNextInvoiceNumber();
|
||||
$data['invoice_date'] = $data['invoice_date'] ?? time();
|
||||
$data['status'] = 'erstellt';
|
||||
$data['fibu_payment_skonto'] = $data['fibu_payment_skonto'] ?? 0;
|
||||
$data['fibu_payment_skonto_rate'] = $data['fibu_payment_skonto_rate'] ?? 0;
|
||||
$data['gesamtrabatt'] = $data['gesamtrabatt'] ?? 0;
|
||||
$data['total'] = $data['total'] ?? 0;
|
||||
$data['total_gross'] = $data['total_gross'] ?? 0;
|
||||
$data['lock'] = 0;
|
||||
$data['exported'] = 0;
|
||||
$data['create_by'] = $me->id;
|
||||
$data['edit_by'] = $me->id;
|
||||
$data['create'] = time();
|
||||
$data['edit'] = time();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -389,9 +419,15 @@ class ManualInvoiceController extends TTCrud
|
||||
unset($data['positions']);
|
||||
}
|
||||
|
||||
if (isset($data['id']) && ($invoice = ManualInvoiceModel::get($data['id'])) && $invoice->status === 'exportiert') {
|
||||
$this->infoMessages['update'] = 'Rechnung wurde bereits exportiert und kann nicht mehr bearbeitet werden';
|
||||
return false;
|
||||
if (isset($data['id']) && ($invoice = ManualInvoiceModel::get($data['id']))) {
|
||||
if ($invoice->lock == 1) {
|
||||
$this->infoMessages['update'] = 'Rechnung ist gesperrt und kann nicht bearbeitet werden';
|
||||
return false;
|
||||
}
|
||||
if ($invoice->status === 'exportiert') {
|
||||
$this->infoMessages['update'] = 'Rechnung wurde bereits exportiert und kann nicht mehr bearbeitet werden';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert invoice_date from string to timestamp if needed
|
||||
@@ -626,6 +662,12 @@ class ManualInvoiceController extends TTCrud
|
||||
|
||||
if (!$originalInvoiceId || empty($positions) || !($originalInvoice = ManualInvoiceModel::get($originalInvoiceId))) {
|
||||
self::returnJson(['success' => false, 'message' => 'Ungültige Anfrage']);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($originalInvoice->lock == 1) {
|
||||
self::returnJson(['success' => false, 'message' => 'Originalrechnung ist gesperrt und kann nicht gutgeschrieben werden']);
|
||||
return;
|
||||
}
|
||||
|
||||
$me = new User();
|
||||
@@ -673,6 +715,8 @@ class ManualInvoiceController extends TTCrud
|
||||
'vatgroup_id' => $originalInvoice->vatgroup_id,
|
||||
'credit_for_invoice_id' => $originalInvoiceId,
|
||||
'status' => 'erstellt',
|
||||
'lock' => 0,
|
||||
'exported' => 0,
|
||||
'create' => time(),
|
||||
'edit' => time(),
|
||||
'create_by' => $me->id,
|
||||
@@ -681,6 +725,7 @@ class ManualInvoiceController extends TTCrud
|
||||
|
||||
if (!($creditInvoiceId = ManualInvoiceModel::create($invoiceData))) {
|
||||
self::returnJson(['success' => false, 'message' => 'Fehler beim Erstellen der Gutschrift']);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($positions as $pos) {
|
||||
@@ -718,7 +763,11 @@ class ManualInvoiceController extends TTCrud
|
||||
protected function beforeDelete(): bool {
|
||||
if ($id = $this->request->id) {
|
||||
$invoice = ManualInvoiceModel::get($id);
|
||||
if ($invoice && $invoice->status === 'exported') {
|
||||
if ($invoice && $invoice->lock == 1) {
|
||||
$this->infoMessages['delete'] = 'Rechnung ist gesperrt und kann nicht gelöscht werden';
|
||||
return false;
|
||||
}
|
||||
if ($invoice && ($invoice->status === 'exported' || $invoice->status === 'exportiert')) {
|
||||
$this->infoMessages['delete'] = 'Rechnung wurde bereits exportiert und kann nicht gelöscht werden';
|
||||
return false;
|
||||
}
|
||||
@@ -732,4 +781,49 @@ class ManualInvoiceController extends TTCrud
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getArticleVatInfoAction() {
|
||||
$articleId = $_GET['article_id'] ?? null;
|
||||
$vatarea = $_GET['vatarea'] ?? 'domestic';
|
||||
|
||||
if (!$articleId) {
|
||||
self::returnJson(['success' => false, 'message' => 'Article ID required']);
|
||||
return;
|
||||
}
|
||||
|
||||
$article = WarehouseArticleModel::get($articleId);
|
||||
if (!$article) {
|
||||
self::returnJson(['success' => false, 'message' => 'Article not found']);
|
||||
return;
|
||||
}
|
||||
|
||||
// Map revenueAccount to vatgroup_id
|
||||
// revenueAccount 0 = Dienstleistungen = vatgroup_id 2
|
||||
// revenueAccount 1 = Handelswaren = vatgroup_id 3
|
||||
$vatgroupId = $article->revenueAccount == 0 ? 2 : 3;
|
||||
|
||||
// Get vatrate for this vatgroup and area
|
||||
$vatrate = VatrateModel::getFirst(['vatgroup_id' => $vatgroupId, 'area' => $vatarea]);
|
||||
|
||||
if (!$vatrate) {
|
||||
self::returnJson(['success' => false, 'message' => 'Vatrate not found for vatgroup ' . $vatgroupId . ' and area ' . $vatarea]);
|
||||
return;
|
||||
}
|
||||
|
||||
self::returnJson([
|
||||
'success' => true,
|
||||
'article' => [
|
||||
'id' => $article->id,
|
||||
'title' => $article->title,
|
||||
'articleNumber' => $article->articleNumber,
|
||||
'description' => $article->description,
|
||||
'revenueAccount' => $article->revenueAccount
|
||||
],
|
||||
'vatgroup_id' => $vatgroupId,
|
||||
'fibu_cost_account' => $vatrate->account,
|
||||
'fibu_cost_account_legacy' => $vatrate->legacy_account,
|
||||
'fibu_taxcode' => $vatrate->taxcode,
|
||||
'vatrate' => $vatrate->rate
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user