getOrderById($order_id); if (!$order->exists()) { throw new Exception('Order not found'); } $economic_module_orders = (new economic_module_orders())->getByOrderId($order_id); $invoice_id = (int)$economic_module_orders->economic_invoice_id->value(); if ($invoice_id > 0) { throw new Exception('An invoice has already been created, invoice ID: ' . $invoice_id); } $order_items = (new orders_o())->getOrderItems($order_id); $order_items = (new orders_o())->applyDepartmentPrices($order_items, $order->department_id->value()); if (count($order_items) === 0) { throw new Exception('No order items found'); } $customer = (new orders_o())->getCustomerByOrderId($order_id); if (!$customer->exists()) { throw new Exception('Customer not found'); } $economic->assertCustomerNumberIsNotDraft((int)$customer->customer_number->value()); $customer_economic = $customer->getCustomerEcocomicData()->economic_customer; $economic_invoice_draft = new economic_invoice_draft_mo(); $economic_invoice_draft->setCustomerNumber((int)$customer_economic->customer_number); $economic_invoice_draft->setRecipient( $customer_economic->name ?? 'Ukendt', $customer_economic->address ?? 'Ukendt', $customer_economic->zip ?? 'Ukendt', $customer_economic->city ?? 'Ukendt' ); $department = (new departments_o())->getDepartmentById($order->department_id->value()); $this->addTheDepartmentDateReference($economic_invoice_draft, $department['name'], $order); $billable_order_items = 0; foreach ($order_items as $order_item) { $added = $this->addOrderItemToInvoice( $customer, $order, $order_item, $economic_invoice_draft, (int)($order_item['quantity'] ?? 1) ); if ($added) { $billable_order_items++; } } if ($billable_order_items < 1) { throw new Exception('No billable order items found'); } $result = null; if ($customer->hasOpenInvoiceDraft() && !$customer->invoicePerOrder()) { $open_invoice_draft = (int)$customer->getOpenInvoiceDraft(); $result = $this->addOrderToInvoiceDraft($open_invoice_draft, $order, $customer, $order_items); } if ($result === null) { $result = $economic_invoice_draft->createInvoiceDraftExample(); } if (!isset($result->draftInvoiceNumber) && !isset($result->lines[0])) { (new logs_o())->add( 'economic_invoice_draft', 'global', 3, $user_id, 'ECONOMIC_INVOICE_DRAFT_EXPORT', 'Failed to create economic invoice draft' ); $message = $result->message ?? 'Failed to create economic invoice draft'; throw new Exception((string)$message); } if ($economic_module_orders->economic_invoice_draft_id->value() > 0) { $economic_invoice_draft->deleteInvoiceDraft($economic_module_orders->economic_invoice_draft_id->value()); } $new_draft_id = (int)($result->draftInvoiceNumber ?? $customer->getOpenInvoiceDraft()); $economic_module_orders->economic_invoice_draft_id->set($new_draft_id); if (!$customer->invoicePerOrder()) { $customer->setOpenInvoiceDraft($new_draft_id); } else { $customer->unsetOpenInvoiceDraft(); } (new logs_o())->add( 'economic_invoice_draft', 'global', 1, $user_id, 'ECONOMIC_INVOICE_DRAFT_EXPORT', 'Successfully exported an economic invoice draft' ); return $economic_module_orders->getArray(); } /** * Export booked invoice from existing draft. * @throws Exception */ public function exportOrderInvoice(int $order_id, int $user_id = 0): array { $economic = new economic(); $order = (new orders_o())->getOrderById($order_id); if (!$order->exists()) { throw new Exception('Order not found'); } $customer = (new orders_o())->getCustomerByOrderId($order_id); if (!$customer->exists()) { throw new Exception('Customer not found'); } $economic->assertCustomerNumberIsNotDraft((int)$customer->customer_number->value()); $economic_module_orders = (new economic_module_orders())->getByOrderId($order_id); if ($economic_module_orders->economic_invoice_draft_id->value() === 0) { throw new Exception('No economic invoice draft found'); } $invoice_id = (int)$economic_module_orders->economic_invoice_id->value(); if ($invoice_id > 0) { throw new Exception('An invoice has already been created, invoice ID: ' . $invoice_id); } $invoice_draft_id = (int)$economic_module_orders->economic_invoice_draft_id->value(); $economic_invoice_draft = new economic_invoice_draft_mo(); $result = $economic_invoice_draft->publishInvoiceDraft($invoice_draft_id); if (!isset($result->bookedInvoiceNumber)) { (new logs_o())->add( 'economic_invoice', 'global', 3, $user_id, 'ECONOMIC_INVOICE_EXPORT', 'Failed to create economic invoice from draft: ' . $invoice_draft_id ); $message = $result->message ?? 'Failed to create economic invoice'; throw new Exception((string)$message); } $economic_module_orders = (new economic_module_orders())->getByOrderId($order_id); $economic_module_orders->economic_invoice_id->set((int)$result->bookedInvoiceNumber); $customer->unsetOpenInvoiceDraft(); (new logs_o())->add( 'economic_invoice', 'global', 1, $user_id, 'ECONOMIC_INVOICE_EXPORT', 'Successfully exported an economic invoice' ); return $economic_module_orders->getArray(); } /** * Export collected invoice to e-conomic. * @throws Exception */ public function exportCollectedInvoice(int $collected_invoice_id, bool $send_as_is = false, int $user_id = 0): array { $collected_order_invoices = (new collected_order_invoices_o())->select($collected_invoice_id); $collected_order_invoices->requireSelected(); (new economic())->assertCustomerNumberIsNotDraft((int)$collected_order_invoices->customer_number->value()); if ($collected_order_invoices->external_id->value() === null) { if (!$send_as_is) { $customer_fixed_pricing_o = new customer_fixed_pricing_o(); if ($customer_fixed_pricing_o->doesUserHaveFixedPricing((int)$collected_order_invoices->customer_number->value())) { $customer_fixed_pricing_price = $customer_fixed_pricing_o->selectByCustomerNumber((int)$collected_order_invoices->customer_number->value()); $customer_fixed_pricing_price = (int)$customer_fixed_pricing_price->price->value(); $collected_order_invoices->overridePricesFixed($customer_fixed_pricing_price); } else { $collected_order_invoices->addVehicleSubscriptionsTransaction(); } } else { $collected_order_invoices->removeSpecialArrangements(); $collected_order_invoices->setAllItemsToBeIncludedInInvoice(); } $collected_order_invoices->addToEconomic(); } else { if ($collected_order_invoices->booked_invoice_id->value() !== null) { throw new Exception('Invoice has already been booked'); } if ($collected_order_invoices->isDraftExisting()) { throw new Exception('Invoice draft already exists in E-Conomic'); } $customer_fixed_pricing_o = new customer_fixed_pricing_o(); if ($customer_fixed_pricing_o->doesUserHaveFixedPricing((int)$collected_order_invoices->customer_number->value())) { $customer_fixed_pricing_price = $customer_fixed_pricing_o->selectByCustomerNumber((int)$collected_order_invoices->customer_number->value()); $customer_fixed_pricing_price = (int)$customer_fixed_pricing_price->price->value(); $collected_order_invoices->overridePricesFixed($customer_fixed_pricing_price); } else { $collected_order_invoices->addVehicleSubscriptionsTransaction(); } $collected_order_invoices->addToEconomic(true); } (new logs_o())->add( 'orderInvoices', 'global', 1, $user_id, 'ADD_COLLECTED_INVOICE_ECONOMIC', 'Queued transfer processed successfully for collected invoice #' . $collected_invoice_id ); return $collected_order_invoices->asArray(); } /** * @throws Exception */ public function addTheDepartmentDateReference(economic_invoice_draft_mo $economic_invoice_draft, mixed $department_name, orders_o $order): void { $parsed_date = date('d/m/Y H:i', strtotime($order->created_at->value())); $economic_invoice_draft->addLineTEXT("[ " . $parsed_date . ' ' . $department_name . ' #' . $order->id . " ]"); if ($order->reference->value() !== '') { $economic_invoice_draft->addLineTEXT('Reference:'); if (str_contains($order->reference->value(), "\n")) { foreach (explode("\n", $order->reference->value()) as $line) { $economic_invoice_draft->addLineTEXT('# ' . $line); } } else { $economic_invoice_draft->addLineTEXT('# ' . $order->reference->value()); } } $line_reg = ''; if ($order->reg_1->value() !== '') { $line_reg .= 'Reg 1: ' . strtoupper($order->reg_1->value()); } if ($order->reg_2->value() !== '') { $line_reg .= ', Reg 2: ' . strtoupper($order->reg_2->value()); } if ($order->reg_3->value() !== '') { $line_reg .= ', Reg 3: ' . strtoupper($order->reg_3->value()); } $economic_invoice_draft->addLineTEXT($line_reg); if ($order->notes->value() !== '') { $economic_invoice_draft->addLineTEXT('Notat:'); if (str_contains($order->notes->value(), "\n")) { foreach (explode("\n", $order->notes->value()) as $line) { $economic_invoice_draft->addLineTEXT('# ' . $line); } } else { $economic_invoice_draft->addLineTEXT('# ' . $order->notes->value()); } } } /** * Returns true when a product line was added, false when skipped. * @throws Exception */ public function addOrderItemToInvoice( users_o $customer, orders_o $order, mixed $order_item, economic_invoice_draft_mo $economic_invoice_draft, int $quantity = 1 ): bool { if (self::shouldSkipOrderItemForInvoice($order_item, $quantity)) { return false; } if (!is_array($order_item)) { throw new Exception('Order item payload must be an array'); } $product_number = trim((string)($order_item['product']['economic_product_id'] ?? '')); if ($product_number === '') { throw new Exception('Order item is missing economic product id'); } $product_name = trim((string)($order_item['product']['name'] ?? '')); if ($product_name === '') { $product_name = 'Ukendt produkt'; } $reference = isset($order_item['reference']) ? (string)$order_item['reference'] : ''; $notes = isset($order_item['notes']) ? (string)$order_item['notes'] : ''; $department = $order->getDepartmentByOrderId($order->id); $economic_department_id = $department['economic_department_id']; $economic_dimension_id = $department['economic_dimension_id'] ?? 0; $order_item_price = (float)($order_item['price'] ?? 0); $product_price = (float)($order_item['product']['price'] ?? 0); $economic_invoice_draft->addLine( $product_number, $product_name, $quantity, $order_item_price, 0, (int)$economic_department_id ?? 0, (int)$economic_dimension_id ?? 0 ); $show_discount = abs($order_item_price - $product_price) > 0.00001; if ($show_discount && abs($product_price) > 0.00001) { $discount_percentage = round((($product_price - $order_item_price) / $product_price) * 100, 0); $economic_invoice_draft->addLineTEXT('Rabat: ' . ($order_item_price - $product_price) . ' DKK (' . $discount_percentage . '%)'); } if ($reference !== '') { $economic_invoice_draft->addLineTEXT('Reference:'); if (str_contains($reference, "\n")) { foreach (explode("\n", $reference) as $line) { $economic_invoice_draft->addLineTEXT('# ' . $line); } } else { $economic_invoice_draft->addLineTEXT('# ' . $reference); } } if ($customer->doesUserHaveAttribute('requiresRegistrationNumbersInvoice')) { $line_reg = ''; if ($order->reg_1->value() !== '') { $line_reg .= 'Reg 1: ' . strtoupper($order->reg_1->value()); } if ($order->reg_2->value() !== '') { $line_reg .= ', Reg 2: ' . strtoupper($order->reg_2->value()); } if ($order->reg_3->value() !== '') { $line_reg .= ', Reg 3: ' . strtoupper($order->reg_3->value()); } $economic_invoice_draft->addLineTEXT($line_reg); } if ($notes !== '') { $economic_invoice_draft->addLineTEXT('Notat:'); if (str_contains($notes, "\n")) { foreach (explode("\n", $notes) as $line) { $economic_invoice_draft->addLineTEXT('# ' . $line); } } else { $economic_invoice_draft->addLineTEXT('# ' . $notes); } } return true; } /** * @throws Exception */ public function addOrderToInvoiceDraft(int $economic_invoice_draft_id, orders_o $order, users_o $customer, array $order_items): object { $has_billable_items = false; foreach ($order_items as $order_item) { if (!self::shouldSkipOrderItemForInvoice($order_item, (int)($order_item['quantity'] ?? 1))) { $has_billable_items = true; break; } } if (!$has_billable_items) { throw new Exception('No billable order items found'); } $economic_invoice_draft = new economic_invoice_draft_mo(); $economic_invoice_draft->addLineTEXT(''); $economic_invoice_draft->addLineTEXT(''); $this->addTheDepartmentDateReference($economic_invoice_draft, $order->getDepartmentByOrderId($order->id)['name'], $order); foreach ($order_items as $order_item) { $this->addOrderItemToInvoice($customer, $order, $order_item, $economic_invoice_draft, (int)($order_item['quantity'] ?? 1)); } return $economic_invoice_draft->addLinesToInvoiceDraft($economic_invoice_draft_id); } /** * Skip item lines that are not billable in e-conomic export (0 quantity or 0 unit cost). */ public static function shouldSkipOrderItemForInvoice(mixed $order_item, int $quantity = 1): bool { if (!is_array($order_item)) { return true; } $line_quantity = $quantity; if (isset($order_item['quantity']) && is_numeric($order_item['quantity'])) { $line_quantity = (int)$order_item['quantity']; } if ($line_quantity <= 0) { return true; } $line_price = null; if (isset($order_item['price']) && is_numeric($order_item['price'])) { $line_price = (float)$order_item['price']; } if ($line_price === null) { return true; } if (abs($line_price) < 0.00001) { return true; } return false; } }