|
|
|
|
@@ -105,8 +105,8 @@ class ManualInvoiceController extends TTCrud
|
|
|
|
|
"{{ billingAccount }}" => $invoice->fibu_account_number ?? '',
|
|
|
|
|
"{{ invoiceNumber }}" => $invoice->invoice_number ?? "VORSCHAU",
|
|
|
|
|
"{{ invoiceDate }}" => date("d.m.Y", $invoice->invoice_date ?? time()),
|
|
|
|
|
"{{ leistungszeitraumHtml }}" => ($invoice->leistungszeitraum ?? '') ? "<tr><td>Leistungszeitraum:</td><td>" . htmlspecialchars($invoice->leistungszeitraum) . "</td></tr>" : "",
|
|
|
|
|
"{{ externeReferenzHtml }}" => ($invoice->externe_referenz ?? '') ? "<tr><td>Externe Referenz:</td><td>" . htmlspecialchars($invoice->externe_referenz) . "</td></tr>" : "",
|
|
|
|
|
"{{ leistungszeitraumHtml }}" => ($invoice->performance_period ?? '') ? "<tr><td>Leistungszeitraum:</td><td>" . htmlspecialchars($invoice->performance_period) . "</td></tr>" : "",
|
|
|
|
|
"{{ externeReferenzHtml }}" => ($invoice->external_reference ?? '') ? "<tr><td>Externe Referenz:</td><td>" . htmlspecialchars($invoice->external_reference) . "</td></tr>" : "",
|
|
|
|
|
"{{ vatHtml }}" => ($invoice->uid ?? '') ? "<tr><td>Ihre UID:</td><td>" . $invoice->uid . "</td></tr>" : "",
|
|
|
|
|
"{{ qrCodeHtml }}" => ($invoice->total_gross ?? 0) >= 0
|
|
|
|
|
? '<td style="vertical-align: top; padding-right: 10px;"><img alt="QR-Code" src="' . $this->generateSepaQRCode($invoice->invoice_number ?? "VORSCHAU", round($invoice->total_gross ?? 0, 2)) . '" style="display: block; height: 100%; max-height: 3.5cm; width: auto;"></td>'
|
|
|
|
|
@@ -393,11 +393,32 @@ class ManualInvoiceController extends TTCrud
|
|
|
|
|
$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_discount'] = $data['total_discount'] ?? $data['gesamtrabatt'] ?? 0;
|
|
|
|
|
$data['performance_period'] = $data['performance_period'] ?? $data['leistungszeitraum'] ?? null;
|
|
|
|
|
$data['introductory_text'] = $data['introductory_text'] ?? $data['einleitender_text'] ?? null;
|
|
|
|
|
$data['external_reference'] = $data['external_reference'] ?? $data['externe_referenz'] ?? null;
|
|
|
|
|
unset($data['gesamtrabatt'], $data['leistungszeitraum'], $data['einleitender_text'], $data['externe_referenz'], $data['billing_delivery']);
|
|
|
|
|
|
|
|
|
|
$data['total'] = $data['total'] ?? 0;
|
|
|
|
|
$data['total_gross'] = $data['total_gross'] ?? 0;
|
|
|
|
|
$data['lock'] = 0;
|
|
|
|
|
$data['exported'] = 0;
|
|
|
|
|
|
|
|
|
|
if (($data['billing_type'] ?? '') === 'sepa' && ($data['billingaddress_id'] ?? null)) {
|
|
|
|
|
$address = new Address($data['billingaddress_id']);
|
|
|
|
|
if ($address->id) {
|
|
|
|
|
$data['bank_account_bank'] = $address->bank_account_bank;
|
|
|
|
|
$data['bank_account_owner'] = $address->bank_account_owner;
|
|
|
|
|
$data['bank_account_iban'] = str_replace(' ', '', $address->bank_account_iban ?? '');
|
|
|
|
|
$data['bank_account_bic'] = str_replace(' ', '', $address->bank_account_bic ?? '');
|
|
|
|
|
if ($address->sepa_date) {
|
|
|
|
|
$data['sepa_date'] = date('Y-m-d', $address->sepa_date);
|
|
|
|
|
}
|
|
|
|
|
$data['sepa_id'] = 'R' . ($data['fibu_account_number'] ?? '');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$data['create_by'] = $me->id;
|
|
|
|
|
$data['edit_by'] = $me->id;
|
|
|
|
|
$data['create'] = time();
|
|
|
|
|
@@ -476,31 +497,40 @@ class ManualInvoiceController extends TTCrud
|
|
|
|
|
$me = new User();
|
|
|
|
|
$me->loadMe();
|
|
|
|
|
|
|
|
|
|
// Fields that exist in ManualInvoicepositionModel
|
|
|
|
|
$allowedFields = ['billing_id', 'contract_id', 'matchcode', 'product_id', 'product_name', 'product_info',
|
|
|
|
|
'amount', 'unit', 'price', 'discount', 'price_total', 'price_gross', 'vatrate',
|
|
|
|
|
'fibu_cost_account', 'fibu_cost_account_legacy', 'fibu_taxcode', 'options'];
|
|
|
|
|
|
|
|
|
|
foreach ($this->tempPositions as $position) {
|
|
|
|
|
// Skip empty positions
|
|
|
|
|
if (empty($position['product_name']) || ($position['amount'] ?? 0) == 0) continue;
|
|
|
|
|
$articleName = $position['warehousearticle_name'] ?? $position['product_name'] ?? '';
|
|
|
|
|
if (empty($articleName) || ($position['amount'] ?? 0) == 0) continue;
|
|
|
|
|
|
|
|
|
|
// Map _group to position_group
|
|
|
|
|
$groupName = $position['_group'] ?? null;
|
|
|
|
|
$amount = floatval($position['amount']);
|
|
|
|
|
$price = floatval($position['price']);
|
|
|
|
|
$discount = floatval($position['discount'] ?? 0);
|
|
|
|
|
$vatrate = floatval($position['vatrate'] ?? 0);
|
|
|
|
|
$priceAfterDiscount = $amount * $price * (1 - $discount / 100);
|
|
|
|
|
$priceGross = $priceAfterDiscount * (1 + $vatrate / 100);
|
|
|
|
|
|
|
|
|
|
// Filter to only allowed fields
|
|
|
|
|
$filteredPosition = array_intersect_key($position, array_flip($allowedFields));
|
|
|
|
|
|
|
|
|
|
ManualInvoicepositionModel::create(array_merge([
|
|
|
|
|
ManualInvoicepositionModel::create([
|
|
|
|
|
'manualinvoice_id' => $invoiceId,
|
|
|
|
|
'position_group' => $groupName,
|
|
|
|
|
'unit' => 'Stk.',
|
|
|
|
|
'discount' => 0,
|
|
|
|
|
'position_group' => $position['_group'] ?? null,
|
|
|
|
|
'matchcode' => $position['matchcode'] ?? null,
|
|
|
|
|
'warehousearticle_id' => $position['warehousearticle_id'] ?? $position['product_id'] ?? 0,
|
|
|
|
|
'warehousearticle_name' => $articleName,
|
|
|
|
|
'product_info' => $position['product_info'] ?? '',
|
|
|
|
|
'amount' => $amount,
|
|
|
|
|
'unit' => $position['unit'] ?? 'Stk.',
|
|
|
|
|
'price' => $price,
|
|
|
|
|
'discount' => $discount,
|
|
|
|
|
'price_total' => $priceAfterDiscount,
|
|
|
|
|
'price_gross' => $priceGross,
|
|
|
|
|
'vatrate' => $vatrate,
|
|
|
|
|
'fibu_cost_account' => $position['fibu_cost_account'] ?? null,
|
|
|
|
|
'fibu_cost_account_legacy' => $position['fibu_cost_account_legacy'] ?? null,
|
|
|
|
|
'fibu_taxcode' => $position['fibu_taxcode'] ?? null,
|
|
|
|
|
'options' => $position['options'] ?? null,
|
|
|
|
|
'create_by' => $me->id,
|
|
|
|
|
'edit_by' => $me->id,
|
|
|
|
|
'create' => time(),
|
|
|
|
|
'edit' => time()
|
|
|
|
|
], $filteredPosition));
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
$this->tempPositions = [];
|
|
|
|
|
}
|
|
|
|
|
@@ -510,17 +540,13 @@ class ManualInvoiceController extends TTCrud
|
|
|
|
|
|
|
|
|
|
$positions = ManualInvoicepositionModel::search(['manualinvoice_id' => $invoiceId]);
|
|
|
|
|
$subtotal = array_sum(array_column($positions, 'price_total'));
|
|
|
|
|
$totalDiscount = $invoice->total_discount ?? 0;
|
|
|
|
|
$netTotal = $subtotal * (1 - $totalDiscount / 100);
|
|
|
|
|
|
|
|
|
|
// Apply gesamtrabatt (total discount) if exists
|
|
|
|
|
$gesamtrabatt = $invoice->gesamtrabatt ?? 0;
|
|
|
|
|
$discountAmount = $subtotal * ($gesamtrabatt / 100);
|
|
|
|
|
$netTotal = $subtotal - $discountAmount;
|
|
|
|
|
|
|
|
|
|
// Calculate gross total with VAT applied after discount
|
|
|
|
|
$grossTotal = 0;
|
|
|
|
|
foreach ($positions as $pos) {
|
|
|
|
|
$positionNet = $pos->price_total;
|
|
|
|
|
$positionAfterDiscount = $positionNet * (1 - $gesamtrabatt / 100);
|
|
|
|
|
$positionAfterDiscount = $positionNet * (1 - $totalDiscount / 100);
|
|
|
|
|
$grossTotal += $positionAfterDiscount * (1 + $pos->vatrate / 100);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -582,11 +608,11 @@ class ManualInvoiceController extends TTCrud
|
|
|
|
|
'id' => $pos->id,
|
|
|
|
|
'manualinvoice_id' => $pos->manualinvoice_id,
|
|
|
|
|
'_group' => $pos->position_group ?? '',
|
|
|
|
|
'billing_id' => $pos->billing_id,
|
|
|
|
|
'contract_id' => $pos->contract_id,
|
|
|
|
|
'matchcode' => $pos->matchcode,
|
|
|
|
|
'product_id' => $pos->product_id,
|
|
|
|
|
'product_name' => $pos->product_name,
|
|
|
|
|
'warehousearticle_id' => $pos->warehousearticle_id,
|
|
|
|
|
'warehousearticle_name' => $pos->warehousearticle_name,
|
|
|
|
|
'product_id' => $pos->warehousearticle_id,
|
|
|
|
|
'product_name' => $pos->warehousearticle_name,
|
|
|
|
|
'product_info' => $pos->product_info,
|
|
|
|
|
'amount' => $pos->amount,
|
|
|
|
|
'unit' => $pos->unit ?? 'Stk.',
|
|
|
|
|
@@ -632,19 +658,20 @@ class ManualInvoiceController extends TTCrud
|
|
|
|
|
|
|
|
|
|
foreach ($existingCredits as $credit) {
|
|
|
|
|
foreach ($credit->getProperty('positions') as $creditPos) {
|
|
|
|
|
$key = $creditPos->product_id . '_' . $creditPos->matchcode;
|
|
|
|
|
$key = $creditPos->warehousearticle_id . '_' . $creditPos->matchcode;
|
|
|
|
|
$creditedAmounts[$key] = ($creditedAmounts[$key] ?? 0) + abs($creditPos->amount);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$availablePositions = [];
|
|
|
|
|
foreach ($positions as $pos) {
|
|
|
|
|
$key = $pos->product_id . '_' . $pos->matchcode;
|
|
|
|
|
$key = $pos->warehousearticle_id . '_' . $pos->matchcode;
|
|
|
|
|
$availableAmount = $pos->amount - ($creditedAmounts[$key] ?? 0);
|
|
|
|
|
if ($availableAmount > 0) {
|
|
|
|
|
$availablePositions[] = [
|
|
|
|
|
'id' => $pos->id,
|
|
|
|
|
'product_name' => $pos->product_name,
|
|
|
|
|
'warehousearticle_name' => $pos->warehousearticle_name,
|
|
|
|
|
'product_name' => $pos->warehousearticle_name,
|
|
|
|
|
'product_info' => $pos->product_info,
|
|
|
|
|
'original_amount' => $pos->amount,
|
|
|
|
|
'credited_amount' => $creditedAmounts[$key] ?? 0,
|
|
|
|
|
@@ -652,7 +679,8 @@ class ManualInvoiceController extends TTCrud
|
|
|
|
|
'unit' => $pos->unit ?? 'Stk.',
|
|
|
|
|
'price' => $pos->price,
|
|
|
|
|
'vatrate' => $pos->vatrate,
|
|
|
|
|
'product_id' => $pos->product_id,
|
|
|
|
|
'warehousearticle_id' => $pos->warehousearticle_id,
|
|
|
|
|
'product_id' => $pos->warehousearticle_id,
|
|
|
|
|
'matchcode' => $pos->matchcode,
|
|
|
|
|
'fibu_cost_account' => $pos->fibu_cost_account,
|
|
|
|
|
'fibu_taxcode' => $pos->fibu_taxcode
|
|
|
|
|
@@ -692,10 +720,10 @@ class ManualInvoiceController extends TTCrud
|
|
|
|
|
$invoiceData = [
|
|
|
|
|
'invoice_number' => ManualInvoiceModel::getNextInvoiceNumber(),
|
|
|
|
|
'invoice_date' => time(),
|
|
|
|
|
'leistungszeitraum' => $originalInvoice->leistungszeitraum ?? null,
|
|
|
|
|
'einleitender_text' => 'Gutschrift zur Rechnung ' . $originalInvoice->invoice_number,
|
|
|
|
|
'externe_referenz' => $originalInvoice->externe_referenz ?? null,
|
|
|
|
|
'gesamtrabatt' => 0,
|
|
|
|
|
'performance_period' => $originalInvoice->performance_period ?? null,
|
|
|
|
|
'introductory_text' => 'Gutschrift zur Rechnung ' . $originalInvoice->invoice_number,
|
|
|
|
|
'external_reference' => $originalInvoice->external_reference ?? null,
|
|
|
|
|
'total_discount' => 0,
|
|
|
|
|
'owner_id' => $originalInvoice->owner_id,
|
|
|
|
|
'billingaddress_id' => $originalInvoice->billingaddress_id,
|
|
|
|
|
'customer_number' => $originalInvoice->customer_number,
|
|
|
|
|
@@ -721,7 +749,6 @@ class ManualInvoiceController extends TTCrud
|
|
|
|
|
'email' => $originalInvoice->email,
|
|
|
|
|
'uid' => $originalInvoice->uid,
|
|
|
|
|
'billing_type' => $originalInvoice->billing_type,
|
|
|
|
|
'billing_delivery' => $originalInvoice->billing_delivery,
|
|
|
|
|
'bank_account_bank' => $originalInvoice->bank_account_bank,
|
|
|
|
|
'bank_account_owner' => $originalInvoice->bank_account_owner,
|
|
|
|
|
'bank_account_iban' => $originalInvoice->bank_account_iban,
|
|
|
|
|
@@ -749,8 +776,8 @@ class ManualInvoiceController extends TTCrud
|
|
|
|
|
ManualInvoicepositionModel::create([
|
|
|
|
|
'manualinvoice_id' => $creditInvoiceId,
|
|
|
|
|
'position_group' => null,
|
|
|
|
|
'product_id' => $pos['product_id'],
|
|
|
|
|
'product_name' => $pos['product_name'],
|
|
|
|
|
'warehousearticle_id' => $pos['warehousearticle_id'] ?? $pos['product_id'] ?? 0,
|
|
|
|
|
'warehousearticle_name' => $pos['warehousearticle_name'] ?? $pos['product_name'] ?? '',
|
|
|
|
|
'product_info' => $pos['product_info'] ?? '',
|
|
|
|
|
'amount' => -abs($pos['amount']),
|
|
|
|
|
'unit' => $pos['unit'] ?? 'Stk.',
|
|
|
|
|
@@ -762,8 +789,6 @@ class ManualInvoiceController extends TTCrud
|
|
|
|
|
'matchcode' => $pos['matchcode'] ?? null,
|
|
|
|
|
'fibu_cost_account' => $pos['fibu_cost_account'] ?? null,
|
|
|
|
|
'fibu_taxcode' => $pos['fibu_taxcode'] ?? null,
|
|
|
|
|
'contract_id' => 0,
|
|
|
|
|
'billing_id' => null,
|
|
|
|
|
'create_by' => $me->id,
|
|
|
|
|
'edit_by' => $me->id,
|
|
|
|
|
'create' => time(),
|
|
|
|
|
@@ -813,12 +838,7 @@ class ManualInvoiceController extends TTCrud
|
|
|
|
|
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
|
|
|
|
|
$vatgroupId = $article->vatgroup_id;
|
|
|
|
|
$vatrate = VatrateModel::getFirst(['vatgroup_id' => $vatgroupId, 'area' => $vatarea]);
|
|
|
|
|
|
|
|
|
|
if (!$vatrate) {
|
|
|
|
|
@@ -826,7 +846,6 @@ class ManualInvoiceController extends TTCrud
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Parse prices from cheapestSellPrice JSON
|
|
|
|
|
$prices = [];
|
|
|
|
|
if (!empty($article->cheapestSellPrice)) {
|
|
|
|
|
$pricesData = json_decode($article->cheapestSellPrice, true);
|
|
|
|
|
@@ -842,7 +861,7 @@ class ManualInvoiceController extends TTCrud
|
|
|
|
|
'title' => $article->title,
|
|
|
|
|
'articleNumber' => $article->articleNumber,
|
|
|
|
|
'description' => $article->description,
|
|
|
|
|
'revenueAccount' => $article->revenueAccount,
|
|
|
|
|
'vatgroup_id' => $article->vatgroup_id,
|
|
|
|
|
'unit' => $article->unit
|
|
|
|
|
],
|
|
|
|
|
'prices' => $prices,
|
|
|
|
|
|