Add shipping note import to manual invoice

This commit is contained in:
2025-12-09 12:23:53 +01:00
parent 7035f01fad
commit 2690451f0b
3 changed files with 322 additions and 3 deletions

View File

@@ -34,6 +34,14 @@ class WarehouseShippingNoteController extends TTCrud {
'delete' => 'Lieferschein wurde gelöscht',
'noChanges' => 'Keine Änderungen vorgenommen'];
protected array $permissionCheck = ['WarehouseUser'];
protected array $additionalActions = [
[
'key' => 'createManualInvoice',
'title' => 'Rechnung erstellen',
'class' => 'fas fa-file-invoice text-primary',
'condition' => ['status' => 'accepted']
]
];
//@formatter:on
protected function prepareCrudConfig() {
@@ -109,6 +117,177 @@ class WarehouseShippingNoteController extends TTCrud {
));
}
protected function getShippingNoteForInvoiceAction() {
$id = $this->request->id;
// Get shipping note
$shippingNote = WarehouseShippingNoteModel::get($id);
if (!$shippingNote) {
self::returnJson(['success' => false, 'message' => 'Lieferschein nicht gefunden']);
return;
}
// Get billing address info
$billingAddress = null;
if ($shippingNote->billingAddressId) {
$billingAddress = Address::getOne($shippingNote->billingAddressId);
}
// Determine price type ONCE (not in loop for performance)
$priceType = 'Verkauf';
if ($shippingNote->billingAddressId) {
$addressPriceType = AddressPriceTypeModel::getFirst(['address_id' => $shippingNote->billingAddressId]);
if ($addressPriceType) {
$warehousePriceType = WarehouseArticlePriceTypeModel::get($addressPriceType->priceType_id);
if ($warehousePriceType) {
$priceType = $warehousePriceType->title;
}
}
}
// Decode and enrich positions
$positions = json_decode($shippingNote->positions, true);
if (!is_array($positions)) {
$positions = [];
}
$enrichedPositions = [];
foreach ($positions as $position) {
if (isset($position['article'])) {
// Fetch article details
$article = WarehouseArticleModel::get($position['article']);
if (!$article) continue;
// Get price for determined price type
$prices = json_decode($article->cheapestSellPrice, true) ?: [];
$price = 0;
foreach ($prices as $p) {
if ($p['title'] === $priceType) {
$price = $p['price'];
break;
}
}
$enrichedPositions[] = [
'type' => 'article',
'articleId' => $article->id,
'product_name' => $article->articleNumber . " | " . $article->title,
'product_info' => $article->description,
'amount' => $position['amount'],
'unit' => $article->unit,
'price' => $price,
'discount' => 0,
'vatrate' => 20
];
} elseif (isset($position['articlePacket'])) {
// Handle article packets
$packet = WarehouseArticlePacketModel::get($position['articlePacket']);
if (!$packet) continue;
$enrichedPositions[] = [
'type' => 'packet',
'packetId' => $packet->id,
'product_name' => $packet->title,
'product_info' => $packet->description ?? '',
'amount' => $position['amount'],
'unit' => 'Pau.',
'price' => 0,
'discount' => 0,
'vatrate' => 20
];
} elseif (isset($position['articleText'])) {
// Handle custom text entries
$enrichedPositions[] = [
'type' => 'text',
'product_name' => $position['articleText'],
'product_info' => '',
'amount' => $position['amount'] ?? 1,
'unit' => 'Stk.',
'price' => 0,
'discount' => 0,
'vatrate' => 20
];
}
}
// Add hours entries as positions
$hoursEntries = json_decode($shippingNote->hoursEntries, true);
if (!is_array($hoursEntries)) {
$hoursEntries = [];
}
foreach ($hoursEntries as $hoursEntry) {
if (empty($hoursEntry['hourCount']) || floatval(str_replace(",", ".", $hoursEntry['hourCount'])) <= 0) {
continue;
}
$userName = 'Unbekannt';
if (!empty($hoursEntry['userId']) && is_numeric($hoursEntry['userId'])) {
try {
$user = UserModel::getOne($hoursEntry['userId']);
$userName = $user ? $user->name : 'Unbekannt';
} catch (Exception $e) {
$userName = 'Unbekannt';
}
} elseif (!empty($hoursEntry['userId_text'])) {
$userName = $hoursEntry['userId_text'];
}
$enrichedPositions[] = [
'type' => 'hours',
'product_name' => 'Arbeitsstunden - ' . $userName,
'product_info' => 'Datum: ' . (isset($hoursEntry['date']) ? date('d.m.Y', strtotime($hoursEntry['date'])) : ''),
'amount' => str_replace(",", ".", $hoursEntry['hourCount']),
'unit' => 'h',
'price' => 60,
'discount' => 0,
'vatrate' => 20
];
}
self::returnJson([
'success' => true,
'data' => [
'shippingNoteId' => $shippingNote->id,
'billingAddress' => $billingAddress ? [
'id' => $billingAddress->id,
'customer_number' => $billingAddress->customer_number,
'company' => $billingAddress->company,
'firstname' => $billingAddress->firstname,
'lastname' => $billingAddress->lastname,
'street' => $billingAddress->street,
'zip' => $billingAddress->zip,
'city' => $billingAddress->city,
'email' => $billingAddress->email,
'uid' => $billingAddress->uid,
'fibu_account_number' => $billingAddress->fibu_account_number,
'billing_type' => $billingAddress->billing_type,
'billing_delivery' => $billingAddress->billing_delivery,
'bank_account_bank' => $billingAddress->bank_account_bank,
'bank_account_owner' => $billingAddress->bank_account_owner,
'bank_account_iban' => $billingAddress->bank_account_iban,
'bank_account_bic' => $billingAddress->bank_account_bic,
'sepa_date' => $billingAddress->sepa_date,
'fibu_payment_due' => $billingAddress->fibu_payment_due,
'fibu_payment_skonto' => $billingAddress->fibu_payment_skonto,
'fibu_payment_skonto_rate' => $billingAddress->fibu_payment_skonto_rate
] : null,
'deliveryAddress' => [
'name' => $shippingNote->deliveryAddressName,
'line' => $shippingNote->deliveryAddressLine,
'plz' => $shippingNote->deliveryAddressPLZ,
'city' => $shippingNote->deliveryAddressCity,
'email' => $shippingNote->deliveryAddressEMail
],
'note' => $shippingNote->note,
'positions' => $enrichedPositions
]
]);
}
protected function getArticleAddressPriceAction() {
empty($this->request->articleId) && $this->sendError('Keine Artikel ID gefunden');
empty($this->request->addressId) && $this->sendError('Keine Adress ID gefunden');