Files
api/services/nginx/app/tests/Unit/Invoicing/EconomicInvoiceDraftItemizedDiscountTest.php
T

127 lines
4.2 KiB
PHP

<?php
app_require('modules/economic/helpers/economic_invoice_draft.php');
use helpers\economic_invoice_draft;
if (!class_exists('EconomicInvoiceDraftItemizedDiscountProbe')) {
class EconomicInvoiceDraftItemizedDiscountProbe extends economic_invoice_draft
{
public array $sentBatches = [];
public function __construct()
{
$this->draft_invoice_number = 123;
$this->currency = 'DKK';
$this->conversion_rate = 1.0;
$this->draft_invoice_data = (object)['draftInvoiceNumber' => 123];
}
protected function sendDraftLines(array $draft_lines): object
{
$this->sentBatches[] = $draft_lines;
return (object)['lines' => $draft_lines];
}
}
}
function economic_itemized_discount_order_item(array $overrides = []): array
{
return array_replace_recursive([
'id' => 123,
'quantity' => 2,
'price' => 80,
'reference' => '',
'notes' => '',
'include_in_invoice' => true,
'product' => [
'economic_product_id' => '5',
'name' => 'Premium wash',
'price' => 100,
],
], $overrides);
}
it('detects billable itemized discounts from original and final prices', function (): void {
$pricing = economic_invoice_draft::resolveOrderItemInvoicePricing(economic_itemized_discount_order_item());
expect($pricing['has_discount'])->toBeTrue()
->and($pricing['original_unit_price'])->toBe(100.0)
->and($pricing['final_unit_price'])->toBe(80.0)
->and($pricing['discount_unit_amount'])->toBe(20.0)
->and($pricing['discount_total_amount'])->toBe(40.0)
->and($pricing['discount_percentage'])->toBe(20.0);
});
it('does not mark equal prices, zero quantities, or zero final prices as itemized discounts', function (): void {
expect(economic_invoice_draft::orderItemHasBillableDiscount(economic_itemized_discount_order_item([
'price' => 100,
])))->toBeFalse();
expect(economic_invoice_draft::orderItemHasBillableDiscount(economic_itemized_discount_order_item([
'quantity' => 0,
])))->toBeFalse();
expect(economic_invoice_draft::orderItemHasBillableDiscount(economic_itemized_discount_order_item([
'price' => 0,
])))->toBeFalse();
});
it('uses original price and exact discount basis for itemized discount product lines', function (): void {
$draft = new EconomicInvoiceDraftItemizedDiscountProbe();
$draft->addOrderItemLine(
economic_itemized_discount_order_item(),
[
'economic_department_id' => 75,
'economic_dimension_id' => 1,
],
false,
true
);
$draft->flushLinesInBatches();
$line = $draft->sentBatches[0][0];
expect($line['product']['productNumber'])->toBe('5')
->and($line['description'])->toBe('Premium wash')
->and($line['quantity'])->toBe(2.0)
->and($line['unitNetPrice'])->toBe(100.0)
->and($line['discountPercentage'])->toBe(20.0);
});
it('keeps non-discount itemized product lines at the exact final price', function (): void {
$draft = new EconomicInvoiceDraftItemizedDiscountProbe();
$draft->addOrderItemLine(
economic_itemized_discount_order_item([
'price' => 125,
'product' => [
'price' => 100,
],
]),
[
'economic_department_id' => 75,
'economic_dimension_id' => 1,
],
false,
true
);
$draft->flushLinesInBatches();
$line = $draft->sentBatches[0][0];
expect($line['unitNetPrice'])->toBe(125.0)
->and($line['discountPercentage'])->toBe(0.0);
});
it('keeps fractional discount percentages instead of rounding itemized discounts to whole percentages', function (): void {
$pricing = economic_invoice_draft::resolveOrderItemInvoicePricing(economic_itemized_discount_order_item([
'quantity' => 1,
'price' => 2,
'product' => [
'price' => 3,
],
]));
expect($pricing['discount_unit_amount'])->toBe(1.0)
->and($pricing['discount_total_amount'])->toBe(1.0)
->and($pricing['discount_percentage'])->toBe(33.3333333333);
});