diff --git a/services/nginx/app/objects/orders_o.php b/services/nginx/app/objects/orders_o.php index 1122ce4c..7bcb167a 100644 --- a/services/nginx/app/objects/orders_o.php +++ b/services/nginx/app/objects/orders_o.php @@ -1332,31 +1332,42 @@ class orders_o extends db { // Get the original net amount for the order items, ignoring any temporary net amount set self::requireSelected(); - $order_items = $this->getOrderItems((int)$this->id); - //echo 'Calculating net amount for order ID ' . $this->id . ' with ' . count($order_items) . " items\n"; - return array_sum(array_map(/** - * @throws Exception - */ function ($item) { - if ( (int)$item['price'] > 0 && (int)$item['quantity'] > 0) { - return (int)$item['price'] * (int)$item['quantity']; + $order_items = (new order_items_o())->getFieldsWhere( + ['order_id' => (int)$this->id], + ['price', 'quantity', 'product_id'] + ); + if (empty($order_items)) { + return 0; + } + + $total = 0; + $department_id = (int)$this->department_id->value(); + $tmp_user = null; + $department_price_cache = []; + + foreach ( $order_items as $item ) { + $price = (int)$item['price']; + $quantity = (int)$item['quantity']; + + if ($price > 0 && $quantity > 0) { + $total += $price * $quantity; + continue; } - // Otherwise we need to get the product price - $product = (new products_o())->select((int)$item['product_id']); - // Apply the customer discount if applicable - $department_price_original = (int)$product->getDepartmentPrice((int)$this->department_id->value()); - // Get the customers user object - $tmp_user = (new users_o())->getUserByCustomerNumber((int)$this->customer_id->value()); - // Get the discount percentage for the customer - $discount = $tmp_user->getCustomPrice((int)$product->id, false); - // Calculate the final price after discount - $post_discount = (int)round($department_price_original * (1 - ($discount / 100))) * (int)$item['quantity']; - //echo 'Adding ' . $post_discount . ' for product ' . $product->name . ' (Original price: ' . $department_price_original . ', Discount: ' . $discount . '%, Quantity: ' . (int)$item['quantity'] . ")\n"; - $actual_price = (int)$item['price']; - if ($actual_price !== $post_discount) { - //echo "Warning: The actual price ($actual_price) does not match the calculated price ($post_discount) for product " . $product->name . "\n"; + + $product_id = (int)$item['product_id']; + if (!isset($department_price_cache[$product_id])) { + $product = (new products_o())->select($product_id); + $department_price_cache[$product_id] = (int)$product->getDepartmentPrice($department_id); } - return $post_discount; - }, $order_items)); + if ($tmp_user === null) { + $tmp_user = (new users_o())->getUserByCustomerNumber((int)$this->customer_id->value()); + } + $discount = $tmp_user->getCustomPrice($product_id, false); + $post_discount = (int)round($department_price_cache[$product_id] * (1 - ($discount / 100))) * $quantity; + $total += $post_discount; + } + + return $total; } /** @@ -1624,4 +1635,4 @@ class orders_o extends db } return $orders; } -} \ No newline at end of file +} diff --git a/services/nginx/app/routes/InvoicingPeriodRoute.php b/services/nginx/app/routes/InvoicingPeriodRoute.php index 082bcff5..98b9caaa 100644 --- a/services/nginx/app/routes/InvoicingPeriodRoute.php +++ b/services/nginx/app/routes/InvoicingPeriodRoute.php @@ -54,6 +54,25 @@ class InvoicingPeriodRoute return self::$departmentExcludedFromInvoicingCache[$departmentId]; } + /** + * Slack summaries are expensive on request latency, so they are opt-in. + * Enable with query param `sendSlackSummary=1` or env `INVOICING_PERIOD_SEND_SLACK_SUMMARY=true`. + */ + private static function shouldSendSlackSummary(): bool + { + $requestOverride = $_GET['sendSlackSummary'] ?? null; + if ($requestOverride !== null) { + return in_array(strtolower((string)$requestOverride), ['1', 'true', 'yes'], true); + } + + $envFlag = getenv('INVOICING_PERIOD_SEND_SLACK_SUMMARY'); + if ($envFlag === false) { + return false; + } + + return in_array(strtolower((string)$envFlag), ['1', 'true', 'yes'], true); + } + /** * @param array $collective_results @@ -538,17 +557,19 @@ class InvoicingPeriodRoute $collective_results['subscription_price_department_distribution_parsed'] = $parsed_distribution; // Include the collective results in the response $response->add_include('collective_subscription_results', $collective_results); - // Send summary to slack - $slack_message = "Subscription Price Distribution Summary:\n"; - $slack_message .= "Total Subscription Price: " . $collective_results['total_subscription_price'] . "\n"; - $slack_message .= "Department Distribution:\n"; - $tmp_total = 0; - foreach ( $collective_results['subscription_price_department_distribution_parsed'] as $department_name => $price ) { - $slack_message .= "- " . $department_name . ": " . $price . "\n"; - $tmp_total += $price; + if (self::shouldSendSlackSummary()) { + // Send summary to slack + $slack_message = "Subscription Price Distribution Summary:\n"; + $slack_message .= "Total Subscription Price: " . $collective_results['total_subscription_price'] . "\n"; + $slack_message .= "Department Distribution:\n"; + $tmp_total = 0; + foreach ( $collective_results['subscription_price_department_distribution_parsed'] as $department_name => $price ) { + $slack_message .= "- " . $department_name . ": " . $price . "\n"; + $tmp_total += $price; + } + $slack_message .= "Total Distribution: " . $tmp_total . "\n"; + (new slack())->send_message($slack_message, 'Subscription Price Distribution Summary'); } - $slack_message .= "Total Distribution: " . $tmp_total . "\n"; - (new slack())->send_message($slack_message, 'Subscription Price Distribution Summary'); return $customersWithSubscriptions; } @@ -740,11 +761,13 @@ class InvoicingPeriodRoute private static function getOriginalPrice(array $fixed_pricing): array { global $response; - $orders = new orders_o(); + $order_items = new order_items_o(); foreach ( $fixed_pricing as &$customer ) { if (isset($customer['meta']['fixed_pricing'])) { $original_price = 0; $department_totals = []; // Array to hold totals per department + + $eligible_transaction_department_ids = []; foreach ( $customer['transactions'] as $transaction ) { $department_id = (int)($transaction['department_id'] ?? 0); $excluded = (bool)($transaction['excluded'] ?? false); @@ -753,16 +776,60 @@ class InvoicingPeriodRoute if ($excluded || $department_id === 10) { continue; } - - $transaction_original_price = $orders->select((int)$transaction['id'])->getNetAmountForOrderItemsOriginal(); - $original_price += $transaction_original_price; - // Initialize the department total if it doesn't exist - if (!isset($department_totals[$department_id])) { - $department_totals[$department_id] = 0; - } - // Add the transaction amount to the department total - $department_totals[$department_id] += $transaction_original_price; + $eligible_transaction_department_ids[(int)$transaction['id']] = $department_id; } + + if (!empty($eligible_transaction_department_ids)) { + $transaction_original_prices = []; + $product_cache = []; + $department_price_cache = []; + $discount_cache = []; + $user = (new users_o())->getUserByCustomerNumber((int)$customer['customer_number']); + $rows = $order_items->getFieldsWhere( + ['order_id' => array_keys($eligible_transaction_department_ids)], + ['order_id', 'product_id', 'price', 'quantity'] + ); + + foreach ( $rows as $row ) { + $order_id = (int)$row['order_id']; + $department_id = (int)($eligible_transaction_department_ids[$order_id] ?? 0); + if ($department_id <= 0) { + continue; + } + $product_id = (int)$row['product_id']; + $price = (int)$row['price']; + $quantity = (int)$row['quantity']; + + if ($price > 0 && $quantity > 0) { + $transaction_original_prices[$order_id] = (int)(($transaction_original_prices[$order_id] ?? 0) + ($price * $quantity)); + continue; + } + + if (!isset($product_cache[$product_id])) { + $product_cache[$product_id] = (new products_o())->select($product_id); + } + if (!isset($department_price_cache[$department_id][$product_id])) { + $department_price_cache[$department_id][$product_id] = (int)$product_cache[$product_id]->getDepartmentPrice($department_id); + } + if (!array_key_exists($product_id, $discount_cache)) { + $discount_cache[$product_id] = $user->getCustomPrice($product_id, false); + } + $post_discount = (int)round($department_price_cache[$department_id][$product_id] * (1 - ($discount_cache[$product_id] / 100))) * $quantity; + $transaction_original_prices[$order_id] = (int)(($transaction_original_prices[$order_id] ?? 0) + $post_discount); + } + + foreach ( $eligible_transaction_department_ids as $transaction_id => $department_id ) { + $transaction_original_price = (int)($transaction_original_prices[$transaction_id] ?? 0); + $original_price += $transaction_original_price; + // Initialize the department total if it doesn't exist + if (!isset($department_totals[$department_id])) { + $department_totals[$department_id] = 0; + } + // Add the transaction amount to the department total + $department_totals[$department_id] += $transaction_original_price; + } + } + $customer['meta']['fixed_pricing']['original_price'] = $original_price; $customer['meta']['fixed_pricing']['department_totals'] = $department_totals; // Take the relative price of the department totals in relation to the fixed price @@ -810,25 +877,27 @@ class InvoicingPeriodRoute $collective_results = self::parseTheDepartmentIdsToDepartmentNames($collective_results); // Include the collective results in the response $response->add_include('collective_fixed_pricing_results', $collective_results); - // Send slack message with the collective results - $slack_message = "Fixed Pricing Invoicing Period Summary:\n"; - $slack_message .= "Total Fixed Price: " . number_format($collective_results['total_fixed_price'], 2) . " DKK\n"; - $slack_message .= "Total Original Price: " . number_format($collective_results['total_original_price'], 2) . " DKK\n"; - $slack_message .= "Department Totals:\n"; - $tmp_sum = 0; - foreach ( $collective_results['total_department_totals_parsed'] as $department_name => $amount ) { - $slack_message .= "- " . $department_name . ": " . number_format($amount, 2) . " DKK\n"; - $tmp_sum += $amount; + if (self::shouldSendSlackSummary()) { + // Send slack message with the collective results + $slack_message = "Fixed Pricing Invoicing Period Summary:\n"; + $slack_message .= "Total Fixed Price: " . number_format($collective_results['total_fixed_price'], 2) . " DKK\n"; + $slack_message .= "Total Original Price: " . number_format($collective_results['total_original_price'], 2) . " DKK\n"; + $slack_message .= "Department Totals:\n"; + $tmp_sum = 0; + foreach ( $collective_results['total_department_totals_parsed'] as $department_name => $amount ) { + $slack_message .= "- " . $department_name . ": " . number_format($amount, 2) . " DKK\n"; + $tmp_sum += $amount; + } + $slack_message .= "Total Department Totals: " . number_format($tmp_sum, 2) . " DKK\n"; + $slack_message .= "Relative Department Totals:\n"; + $tmp_sum = 0; + foreach ( $collective_results['total_department_totals_relative_parsed'] as $department_name => $amount ) { + $slack_message .= "- " . $department_name . ": " . number_format($amount, 2) . " DKK\n"; + $tmp_sum += $amount; + } + $slack_message .= "Total Relative Department Totals: " . number_format($tmp_sum, 2) . " DKK\n"; + (new slack())->send_message($slack_message, 'Fixed Pricing Invoicing Period Summary'); } - $slack_message .= "Total Department Totals: " . number_format($tmp_sum, 2) . " DKK\n"; - $slack_message .= "Relative Department Totals:\n"; - $tmp_sum = 0; - foreach ( $collective_results['total_department_totals_relative_parsed'] as $department_name => $amount ) { - $slack_message .= "- " . $department_name . ": " . number_format($amount, 2) . " DKK\n"; - $tmp_sum += $amount; - } - $slack_message .= "Total Relative Department Totals: " . number_format($tmp_sum, 2) . " DKK\n"; - (new slack())->send_message($slack_message, 'Fixed Pricing Invoicing Period Summary'); return $fixed_pricing; }