Merge branch 'master' into feat/TRU-149-route-scopes
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
# Invoice Discount Format — DRIFT 12 (TRU-73)
|
||||
|
||||
## What changed
|
||||
|
||||
The e-conomic draft invoice now applies the **customer-level discount
|
||||
percentage at the line level** on every line item, so the discount is
|
||||
clearly visible on each service line on the customer's invoice.
|
||||
|
||||
Before this fix, a customer with a global e-conomic discount (e.g. the
|
||||
`kd` customer `35131752` with a 15% discount) would receive an invoice
|
||||
where the discount was only reflected via an aggregate `TotDiscount`
|
||||
line — and crucially, e-conomic's draft invoice **line** API requires
|
||||
`discountPercentage` on each line, so the aggregate line was being
|
||||
ignored entirely. The customer was getting invoiced at full price with
|
||||
no visible discount at all.
|
||||
|
||||
## Invoice layout — before vs after (for Jimmy)
|
||||
|
||||
The example below uses customer `35131752` ("kd") with a 15% global
|
||||
e-conomic discount, ordering one wash line at 100.00 DKK.
|
||||
|
||||
### Before the fix (DRIFT 12 — discount silently dropped)
|
||||
|
||||
```
|
||||
─────────────────────────────────────────
|
||||
Vask 1 × 100,00 DKK 100,00
|
||||
─────────────────────────────────────────
|
||||
Subtotal 100,00 DKK
|
||||
Rabat (15%) 0,00 DKK ← never applied
|
||||
Total 100,00 DKK
|
||||
─────────────────────────────────────────
|
||||
```
|
||||
|
||||
The `Rabat` line was never actually created on the e-conomic side
|
||||
because the customer has a per-line discount configured, not an
|
||||
aggregate one. The customer saw 100,00 DKK with no discount displayed.
|
||||
|
||||
### After the fix (TRU-73)
|
||||
|
||||
```
|
||||
─────────────────────────────────────────
|
||||
Vask (15% rabat) 1 × 100,00 DKK 100,00
|
||||
Rabat: -15,00 DKK (15%)
|
||||
─────────────────────────────────────────
|
||||
Subtotal 100,00 DKK
|
||||
Rabat 15,00 DKK
|
||||
Total 85,00 DKK
|
||||
─────────────────────────────────────────
|
||||
```
|
||||
|
||||
The 15% discount now appears on the wash line itself (via the
|
||||
`discountPercentage` field that e-conomic renders on each line), and
|
||||
the subtotal correctly reflects the 85,00 DKK total the customer owes.
|
||||
|
||||
## How the fix works
|
||||
|
||||
1. The customer discount percentage is resolved from the cached
|
||||
`economicCustomers` record (via Redis when available, otherwise
|
||||
through the live e-conomic API) and threaded through
|
||||
`economic_invoice_draft::addOrderItemLines()` /
|
||||
`addOrderItemLine()`.
|
||||
2. On each line, the customer discount is combined with the per-item
|
||||
discount using `max(per_item, customer)` so the larger discount
|
||||
always wins — the system never accidentally double-discounts a
|
||||
line that already has a per-item price reduction.
|
||||
3. The aggregate `TotDiscount` line is suppressed when the customer
|
||||
has a per-line discount, since e-conomic's draft line API requires
|
||||
`discountPercentage` to be on the line itself.
|
||||
4. The customer discount is clamped to 0..100 to guard against bad
|
||||
data from the e-conomic API.
|
||||
|
||||
## Code paths
|
||||
|
||||
- `services/nginx/app/modules/economic/helpers/economic_invoice_draft.php`
|
||||
— `addOrderItemLines()` and `addOrderItemLine()` now accept a
|
||||
`customer_discount_percentage` argument and combine it with the
|
||||
per-item discount at the line level.
|
||||
- `services/nginx/app/modules/economic/customers/economicCustomers.php`
|
||||
— logs swallowed missing-currency-price errors so silently-missing
|
||||
discounts become visible in the application log.
|
||||
- `services/nginx/app/modules/economic/endpoints/invoices/draft/economic_invoices_draft_endpoint.php`
|
||||
— forwards the customer discount percentage to the draft builder.
|
||||
- `services/nginx/app/objects/collected_order_invoices_o.php`
|
||||
— resolves the customer discount via the Redis cache + e-conomic
|
||||
customer index and passes it to the draft builder.
|
||||
|
||||
## Tests
|
||||
|
||||
- `services/nginx/app/tests/Unit/Invoicing/EconomicInvoiceDraftCustomerDiscountTest.php`
|
||||
— new tests covering the customer 35131752 case (15% global discount,
|
||||
applied at line level) plus edge cases: per-item + customer discount
|
||||
combined, clamping to 0..100, zero-discount baseline.
|
||||
- `services/nginx/app/tests/Unit/Invoicing/EconomicInvoiceDraftDiscountLineModeWiringTest.php`
|
||||
— updated to account for the new parameter and the customer-discount
|
||||
guard on the aggregate `TotDiscount` line.
|
||||
- `services/nginx/app/tests/Unit/Invoicing/CollectedInvoiceEconomicBatchTransferWiringTest.php`
|
||||
— updated to thread the new parameter through the batch transfer
|
||||
pipeline.
|
||||
@@ -76,9 +76,14 @@ class economicCustomers extends economic_m
|
||||
// The discount is global, but e-conomic resolves it through a product-specific
|
||||
// invoice-line template. For foreign-currency customers some templates can fail
|
||||
// if that product has no price in the customer currency, so try a few products
|
||||
// before falling back to zero.
|
||||
// before falling back to zero. We log every swallowed currency-price failure so
|
||||
// silently-missing discounts (e.g. bug #11 customer 35131752 "kd" 15%) become
|
||||
// visible in the application log instead of vanishing into the void.
|
||||
$products = $this->getCustomerProducts($customer_number, 10);
|
||||
$attempted_products = 0;
|
||||
$swallowed_errors = 0;
|
||||
foreach ($this->extractCustomerProductNumbers($products) as $product_number) {
|
||||
$attempted_products++;
|
||||
try {
|
||||
$discount = $this->getCustomerProductDiscount($customer_number, $product_number);
|
||||
return (int)($discount->discountPercentage ?? 0);
|
||||
@@ -86,9 +91,24 @@ class economicCustomers extends economic_m
|
||||
if (!$this->isMissingCurrencyPriceLookupError($exception)) {
|
||||
throw $exception;
|
||||
}
|
||||
$swallowed_errors++;
|
||||
error_log(sprintf(
|
||||
'[economicCustomers] Swallowed missing-currency-price error while resolving discount for customer %d product %d: %s',
|
||||
$customer_number,
|
||||
$product_number,
|
||||
$exception->getMessage()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if ($attempted_products > 0 && $swallowed_errors === $attempted_products) {
|
||||
error_log(sprintf(
|
||||
'[economicCustomers] All %d invoice-line template probes failed with missing currency prices for customer %d; falling back to 0%% discount. Verify "economic_customer_discount_percentage" in e-conomic for this customer.',
|
||||
$attempted_products,
|
||||
$customer_number
|
||||
));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -72,7 +72,7 @@ class economic_invoices_draft_endpoint
|
||||
* @return array{order_count:int,orders_with_invoice_lines:int,line_count:int,batch_count:int,batch_sizes:array<int,int>}
|
||||
* @throws Exception If the request fails
|
||||
*/
|
||||
public function add_orders(int $invoiceDraftId, array $orders, string $currency = 'DKK', int $line_batch_size = 500, bool $use_itemized_discounts = false): array
|
||||
public function add_orders(int $invoiceDraftId, array $orders, string $currency = 'DKK', int $line_batch_size = 500, bool $use_itemized_discounts = false, int $customer_discount_percentage = 0): array
|
||||
{
|
||||
$draftInvoice = (new economic())->getInvoiceDraft($invoiceDraftId, strtoupper($currency), true);
|
||||
$orders_with_invoice_lines = 0;
|
||||
@@ -89,8 +89,8 @@ class economic_invoices_draft_endpoint
|
||||
$orders_with_invoice_lines++;
|
||||
// Add the transaction header (Timestamp, department, etc.)
|
||||
$draftInvoice->addNewTransactionHeader($order);
|
||||
// Add the order lines
|
||||
$draftInvoice->addOrderItemLines($order, $use_itemized_discounts);
|
||||
// Add the order lines (including the customer-level e-conomic discount, if any).
|
||||
$draftInvoice->addOrderItemLines($order, $use_itemized_discounts, $customer_discount_percentage);
|
||||
// Add an empty line, so the invoice is not empty
|
||||
$draftInvoice->addTextLine('');
|
||||
}
|
||||
|
||||
@@ -414,7 +414,7 @@ class economic_invoice_draft
|
||||
* @throws Exception if the order is not found
|
||||
* @throws Exception if the order is not valid
|
||||
*/
|
||||
public function addOrderItemLines(orders_o $order, bool $use_itemized_discounts = false): void
|
||||
public function addOrderItemLines(orders_o $order, bool $use_itemized_discounts = false, int $customer_discount_percentage = 0): void
|
||||
{
|
||||
// Get the order items
|
||||
$order_items = $order->getOrderItems($order->id);
|
||||
@@ -433,18 +433,25 @@ class economic_invoice_draft
|
||||
});
|
||||
// Define the total discount applied to the order
|
||||
$total_discount = 0;
|
||||
// Normalize the customer discount percentage (clamp to 0..100)
|
||||
$customer_discount_percentage = max(0, min(100, $customer_discount_percentage));
|
||||
// Force itemized discount mode when the customer has a global e-conomic discount
|
||||
// so the discount is applied at the line level (e-conomic line API requires per-line
|
||||
// discountPercentage; an aggregate TotDiscount line would be ignored when the
|
||||
// customer does not have a per-line discount configured for the customer).
|
||||
$effective_itemized_discounts = $use_itemized_discounts || $customer_discount_percentage > 0;
|
||||
// Loop through the order items
|
||||
foreach ( $order_items as $order_item ) {
|
||||
if ($this->shouldSkipOrderItemLine($order_item)) {
|
||||
continue;
|
||||
}
|
||||
// Add the order item to the draft invoice
|
||||
self::addOrderItemLine($order_item, $department, false, $use_itemized_discounts);
|
||||
self::addOrderItemLine($order_item, $department, false, $effective_itemized_discounts, $customer_discount_percentage);
|
||||
// Add the line discount to the total discount
|
||||
$total_discount += ($order_item['product']['price'] - $order_item['price']) * $order_item['quantity'];
|
||||
}
|
||||
// If the total discount is greater than 0, add it to the invoice
|
||||
if (!$use_itemized_discounts && $total_discount > 0) {
|
||||
if (!$use_itemized_discounts && $customer_discount_percentage === 0 && $total_discount > 0) {
|
||||
// Add the discount to the invoice
|
||||
self::addProductDiscountLine($total_discount, $department['economic_department_id'] ?? 0, $department['dimension'] ?? 0);
|
||||
}
|
||||
@@ -460,7 +467,7 @@ class economic_invoice_draft
|
||||
* @throws Exception if the order item is not found
|
||||
* @throws Exception if the order item is not valid
|
||||
*/
|
||||
public function addOrderItemLine(array $order_item, array $department, bool $show_discount = false, bool $use_itemized_discount = false): void
|
||||
public function addOrderItemLine(array $order_item, array $department, bool $show_discount = false, bool $use_itemized_discount = false, int $customer_discount_percentage = 0): void
|
||||
{
|
||||
// Check if the order item is valid
|
||||
if (!isset($order_item['id'])) {
|
||||
@@ -474,9 +481,18 @@ class economic_invoice_draft
|
||||
// Get the dimension id
|
||||
$economic_dimension_id = $department['economic_dimension_id'] ?? 0;
|
||||
$pricing = self::resolveOrderItemInvoicePricing($order_item);
|
||||
$discount_percentage = $use_itemized_discount
|
||||
// The customer discount (e.g. kd customer 35131752 with 15% global e-conomic discount)
|
||||
// is applied at the line level. Combined with per-item discounts using max() so the
|
||||
// biggest discount wins, and so we never accidentally apply a 15% discount on top of
|
||||
// an already-discounted per-item price.
|
||||
$customer_discount_percentage = max(0, min(100, $customer_discount_percentage));
|
||||
$itemized_discount_percentage = $use_itemized_discount
|
||||
? $this->resolveItemizedDiscountPercentageForInvoiceCurrency($pricing)
|
||||
: 0;
|
||||
: 0.0;
|
||||
$discount_percentage = (float)max(
|
||||
$itemized_discount_percentage,
|
||||
(float)$customer_discount_percentage
|
||||
);
|
||||
// Add the order item to the draft invoice
|
||||
self::addProductLine(
|
||||
(string)$order_item['product']['economic_product_id'],
|
||||
|
||||
@@ -725,6 +725,52 @@ class collected_order_invoices_o extends db
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the e-conomic customer discount percentage that should be applied at the
|
||||
* line level when building the invoice draft. Caches via Redis to avoid hammering
|
||||
* the e-conomic templates endpoint on every draft sync.
|
||||
*/
|
||||
private static function resolveCustomerDiscountPercentageForDraft(int $customer_number): int
|
||||
{
|
||||
if ($customer_number <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$user = (new users_o())->getUserByCustomerNumber($customer_number);
|
||||
$userId = (int)$user->id;
|
||||
if ($userId > 0 && defined('redis')) {
|
||||
try {
|
||||
$cached = constant('redis')->get_economic_customer_discount_percentage($userId);
|
||||
if ($cached !== null) {
|
||||
return max(0, min(100, (int)$cached));
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// Fall through to the live lookup.
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$discount = (int)(new \customers\economicCustomers())->getCustomerDiscountPercentage($customer_number);
|
||||
} catch (\Throwable $e) {
|
||||
error_log(sprintf(
|
||||
'[collected_order_invoices_o] Failed to resolve e-conomic customer discount for customer %d: %s',
|
||||
$customer_number,
|
||||
$e->getMessage()
|
||||
));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($userId > 0 && defined('redis')) {
|
||||
try {
|
||||
constant('redis')->cache_economic_customer_discount_percentage($userId, $discount);
|
||||
} catch (\Throwable $e) {
|
||||
// Cache failures are non-fatal.
|
||||
}
|
||||
}
|
||||
|
||||
return max(0, min(100, $discount));
|
||||
}
|
||||
|
||||
/**
|
||||
* Require the invoice draft to not already exist
|
||||
* @throws Exception If the request was not successful
|
||||
@@ -964,7 +1010,18 @@ class collected_order_invoices_o extends db
|
||||
break;
|
||||
}
|
||||
}
|
||||
$metrics = (new economic())->invoices->draft->add_orders($draft_id, $order_objects, $currency, 500, $use_itemized_discounts);
|
||||
// Look up the customer-level e-conomic discount (e.g. bug #11 customer 35131752
|
||||
// "kd" 15%). This is applied at the line level so the draft invoice carries the
|
||||
// discount percentage that e-conomic expects for the customer.
|
||||
$customer_discount_percentage = self::resolveCustomerDiscountPercentageForDraft((int)$this->customer_number->value());
|
||||
$metrics = (new economic())->invoices->draft->add_orders(
|
||||
$draft_id,
|
||||
$order_objects,
|
||||
$currency,
|
||||
500,
|
||||
$use_itemized_discounts,
|
||||
$customer_discount_percentage
|
||||
);
|
||||
$this->last_economic_transfer_metrics = [
|
||||
'draft_invoice_id' => $draft_id,
|
||||
'currency' => (string)$currency,
|
||||
|
||||
+7
-3
@@ -14,7 +14,11 @@ it('routes collected invoice draft line uploads through the multi-order batch en
|
||||
|
||||
$methodBlock = substr($content, (int)$start, (int)$end - (int)$start);
|
||||
expect($methodBlock)->toContain('$order_objects = [];')
|
||||
->and($methodBlock)->toContain('$metrics = (new economic())->invoices->draft->add_orders($draft_id, $order_objects, $currency, 500, $use_itemized_discounts);')
|
||||
// Bug #11 customer 35131752 — the customer discount is threaded through add_orders
|
||||
// so the line-level discountPercentage is applied to each line item.
|
||||
->and($methodBlock)->toContain('$customer_discount_percentage = self::resolveCustomerDiscountPercentageForDraft')
|
||||
->and($methodBlock)->toContain('$metrics = (new economic())->invoices->draft->add_orders(')
|
||||
->and($methodBlock)->toContain('$customer_discount_percentage')
|
||||
->and($methodBlock)->toContain('...$metrics')
|
||||
->and($methodBlock)->not->toContain('self::addInvoiceToDraft($order[\'id\'], true, $draft_id, $currency);');
|
||||
});
|
||||
@@ -36,7 +40,7 @@ it('keeps single-order draft uploads as a wrapper around the batch endpoint', fu
|
||||
|
||||
$batchBlock = substr($content, (int)$singleEnd);
|
||||
expect($batchBlock)->toContain('$draftInvoice->flushLinesInBatches($line_batch_size);')
|
||||
->and($batchBlock)->toContain('$draftInvoice->addOrderItemLines($order, $use_itemized_discounts);')
|
||||
->and($batchBlock)->toContain('$draftInvoice->addOrderItemLines($order, $use_itemized_discounts, $customer_discount_percentage);')
|
||||
->and($batchBlock)->toContain("'orders_with_invoice_lines' => \$orders_with_invoice_lines");
|
||||
});
|
||||
|
||||
@@ -50,7 +54,7 @@ it('selects itemized discount mode for collected invoice batch transfers', funct
|
||||
->and($content)->toContain('invoice_discount_layout')
|
||||
->and($content)->toContain('hasDiscountedIncludedInvoiceItems')
|
||||
->and($content)->toContain('orderItemHasBillableDiscount')
|
||||
->and($content)->toContain('$metrics = (new economic())->invoices->draft->add_orders($draft_id, $order_objects, $currency, 500, $use_itemized_discounts);');
|
||||
->and($content)->toContain('$customer_discount_percentage');
|
||||
});
|
||||
|
||||
it('includes collected invoice batch transfer metrics in queue results when available', function (): void {
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Tests for the e-conomic customer-level discount being applied at the line level.
|
||||
*
|
||||
* Regression coverage for bug #11 — E-conomic 15% discount not applied on
|
||||
* customer 35131752 ("kd"). The customer has a 15% global discount configured in
|
||||
* e-conomic, but the invoice was being sent without any discount on the line items.
|
||||
*
|
||||
* The fix threads the customer discount percentage through the draft builder so it
|
||||
* is applied at the line level via the `discountPercentage` field that e-conomic
|
||||
* expects on each line.
|
||||
*/
|
||||
|
||||
app_require('modules/economic/helpers/economic_invoice_draft.php');
|
||||
|
||||
use helpers\economic_invoice_draft;
|
||||
|
||||
if (!class_exists('EconomicInvoiceDraftCustomerDiscountProbe')) {
|
||||
class EconomicInvoiceDraftCustomerDiscountProbe extends economic_invoice_draft
|
||||
{
|
||||
public array $sentBatches = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->draft_invoice_number = 35131752;
|
||||
$this->currency = 'DKK';
|
||||
$this->conversion_rate = 1.0;
|
||||
$this->draft_invoice_data = (object)['draftInvoiceNumber' => 35131752];
|
||||
}
|
||||
|
||||
protected function sendDraftLines(array $draft_lines): object
|
||||
{
|
||||
$this->sentBatches[] = $draft_lines;
|
||||
return (object)['lines' => $draft_lines];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function economic_customer_discount_order_item(float $price, float $product_price, array $overrides = []): array
|
||||
{
|
||||
return array_replace_recursive([
|
||||
'id' => 9001,
|
||||
'quantity' => 1,
|
||||
'price' => $price,
|
||||
'reference' => '',
|
||||
'notes' => '',
|
||||
'include_in_invoice' => true,
|
||||
'product' => [
|
||||
'economic_product_id' => '5',
|
||||
'name' => 'Wash',
|
||||
'price' => $product_price,
|
||||
],
|
||||
], $overrides);
|
||||
}
|
||||
|
||||
it('applies the 15% customer discount to a line item for customer 35131752 "kd"', function (): void {
|
||||
$draft = new EconomicInvoiceDraftCustomerDiscountProbe();
|
||||
|
||||
// Order item is at full price (no per-item discount) — exactly the customer 35131752
|
||||
// case where the 15% global e-conomic discount was silently dropped.
|
||||
$draft->addOrderItemLine(
|
||||
economic_customer_discount_order_item(100.0, 100.0),
|
||||
[
|
||||
'economic_department_id' => 75,
|
||||
'economic_dimension_id' => 1,
|
||||
],
|
||||
false,
|
||||
false,
|
||||
15
|
||||
);
|
||||
$draft->flushLinesInBatches();
|
||||
|
||||
$line = $draft->sentBatches[0][0];
|
||||
expect($line['product']['productNumber'])->toBe('5')
|
||||
->and($line['description'])->toBe('Wash')
|
||||
->and($line['quantity'])->toBe(1.0)
|
||||
->and($line['unitNetPrice'])->toBe(100.0)
|
||||
->and($line['discountPercentage'])->toBe(15.0);
|
||||
});
|
||||
|
||||
it('uses the larger discount when both per-item and customer discounts are present', function (): void {
|
||||
$draft = new EconomicInvoiceDraftCustomerDiscountProbe();
|
||||
|
||||
// Per-item discount = 10%, customer discount = 15% → max(15, 10) = 15.
|
||||
$draft->addOrderItemLine(
|
||||
economic_customer_discount_order_item(90.0, 100.0),
|
||||
[
|
||||
'economic_department_id' => 75,
|
||||
'economic_dimension_id' => 1,
|
||||
],
|
||||
false,
|
||||
true,
|
||||
15
|
||||
);
|
||||
$draft->flushLinesInBatches();
|
||||
|
||||
$line = $draft->sentBatches[0][0];
|
||||
expect($line['unitNetPrice'])->toBe(100.0)
|
||||
->and($line['discountPercentage'])->toBe(15.0);
|
||||
});
|
||||
|
||||
it('uses the per-item discount when it is larger than the customer discount', function (): void {
|
||||
$draft = new EconomicInvoiceDraftCustomerDiscountProbe();
|
||||
|
||||
// Per-item discount = 25%, customer discount = 15% → max(25, 15) = 25.
|
||||
$draft->addOrderItemLine(
|
||||
economic_customer_discount_order_item(75.0, 100.0),
|
||||
[
|
||||
'economic_department_id' => 75,
|
||||
'economic_dimension_id' => 1,
|
||||
],
|
||||
false,
|
||||
true,
|
||||
15
|
||||
);
|
||||
$draft->flushLinesInBatches();
|
||||
|
||||
$line = $draft->sentBatches[0][0];
|
||||
expect($line['unitNetPrice'])->toBe(100.0)
|
||||
->and($line['discountPercentage'])->toBe(25.0);
|
||||
});
|
||||
|
||||
it('clamps the customer discount percentage to the 0..100 range', function (): void {
|
||||
$draft = new EconomicInvoiceDraftCustomerDiscountProbe();
|
||||
|
||||
$draft->addOrderItemLine(
|
||||
economic_customer_discount_order_item(100.0, 100.0),
|
||||
[
|
||||
'economic_department_id' => 75,
|
||||
'economic_dimension_id' => 1,
|
||||
],
|
||||
false,
|
||||
false,
|
||||
150
|
||||
);
|
||||
$draft->flushLinesInBatches();
|
||||
|
||||
$line = $draft->sentBatches[0][0];
|
||||
expect($line['discountPercentage'])->toBe(100.0);
|
||||
});
|
||||
|
||||
it('emits no line discount when both per-item and customer discounts are zero', function (): void {
|
||||
$draft = new EconomicInvoiceDraftCustomerDiscountProbe();
|
||||
|
||||
$draft->addOrderItemLine(
|
||||
economic_customer_discount_order_item(100.0, 100.0),
|
||||
[
|
||||
'economic_department_id' => 75,
|
||||
'economic_dimension_id' => 1,
|
||||
],
|
||||
false,
|
||||
false,
|
||||
0
|
||||
);
|
||||
$draft->flushLinesInBatches();
|
||||
|
||||
$line = $draft->sentBatches[0][0];
|
||||
expect($line['unitNetPrice'])->toBe(100.0)
|
||||
->and($line['discountPercentage'])->toBe(0.0);
|
||||
});
|
||||
|
||||
it('keeps base behavior unchanged when the customer discount is zero', function (): void {
|
||||
$draft = new EconomicInvoiceDraftCustomerDiscountProbe();
|
||||
|
||||
// No customer discount, no per-item discount — unit price should be the final price.
|
||||
$draft->addOrderItemLine(
|
||||
economic_customer_discount_order_item(100.0, 100.0),
|
||||
[
|
||||
'economic_department_id' => 75,
|
||||
'economic_dimension_id' => 1,
|
||||
],
|
||||
false,
|
||||
false,
|
||||
0
|
||||
);
|
||||
$draft->flushLinesInBatches();
|
||||
|
||||
$line = $draft->sentBatches[0][0];
|
||||
expect($line['unitNetPrice'])->toBe(100.0)
|
||||
->and($line['discountPercentage'])->toBe(0.0);
|
||||
});
|
||||
+6
-2
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
it('only adds TotDiscount aggregate line when itemized discounts are disabled', function (): void {
|
||||
it('only adds TotDiscount aggregate line when itemized discounts are disabled and no customer discount is set', function (): void {
|
||||
$content = file_get_contents(app_path('modules/economic/helpers/economic_invoice_draft.php'));
|
||||
|
||||
expect($content)->not->toBeFalse();
|
||||
@@ -13,7 +13,11 @@ it('only adds TotDiscount aggregate line when itemized discounts are disabled',
|
||||
expect($end)->toBeGreaterThan($start);
|
||||
|
||||
$block = substr($content, (int)$start, (int)$end - (int)$start);
|
||||
// The aggregate TotDiscount line is only added when neither itemized discounts
|
||||
// nor a customer-level e-conomic discount is in effect. The customer discount
|
||||
// (e.g. bug #11 customer 35131752 "kd" 15%) is applied at the line level instead.
|
||||
expect($block)
|
||||
->toContain('if (!$use_itemized_discounts && $total_discount > 0)')
|
||||
->toContain('if (!$use_itemized_discounts && $customer_discount_percentage === 0 && $total_discount > 0)')
|
||||
->toContain('self::addProductDiscountLine($total_discount');
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user