- Implement tests for the internet connections module, covering routes, IP range creation, and connection validation. - Add tests for the Invoice2DataService to validate extraction from GlobalConnect invoices. - Create tests for subscription network provisioning, ensuring proper handling of network items and IP allocations. - Include validation checks for subtotal mismatches and ensure error handling for missing IP selections.
798 lines
30 KiB
Python
798 lines
30 KiB
Python
import sys
|
|
from decimal import Decimal
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
|
|
from app.billing.backend import supplier_invoices as supplier_module
|
|
|
|
|
|
def test_sync_globalconnect_extraction_creates_connections_and_ip_ranges(monkeypatch):
|
|
created_connections = []
|
|
created_ranges = []
|
|
ensured_ranges = []
|
|
|
|
extraction = {
|
|
"extraction_id": 176,
|
|
"vendor_name": "GlobalConnect A/S",
|
|
"document_id": "3018657",
|
|
"document_date": "2026-01-01",
|
|
"llm_response_json": {"template": "dk.globalconnect"},
|
|
}
|
|
lines = [
|
|
{
|
|
"description": "100 Mbps fiberforbindelse",
|
|
"provider_reference": "NKA008214",
|
|
"circuit_id": "NKA008214",
|
|
"line_total": 2850.0,
|
|
"unit_price": 950.0,
|
|
"quantity": 3,
|
|
"end_customer_name": "Malerfirmaet Gert Jensen ApS",
|
|
"service_address": "Metalbuen 26, 2750 Ballerup",
|
|
},
|
|
{
|
|
"description": "IPv4 IP-adresser",
|
|
"provider_reference": "NKA008214",
|
|
"circuit_id": "NKA008214",
|
|
"ip_address": "152.115.84.232/29",
|
|
"line_total": 192.0,
|
|
"unit_price": 64.0,
|
|
"quantity": 3,
|
|
"end_customer_name": "Malerfirmaet Gert Jensen ApS",
|
|
"service_address": "Metalbuen 26, 2750 Ballerup",
|
|
},
|
|
]
|
|
|
|
def fake_load_lines(_):
|
|
return lines
|
|
|
|
def fake_load_customers():
|
|
return [{"id": 322, "name": "Malerfirmaet Gert Jensen ApS", "address": "Metalbuen 26", "postal_code": "2750", "city": "Ballerup"}]
|
|
|
|
def fake_execute_query_single(query, params=None):
|
|
if "FROM internet_connections_connections" in query and "WHERE id = %s" in query:
|
|
return {"address": "Metalbuen 26, 2750 Ballerup", "allocation_model": "dedicated"}
|
|
if "FROM internet_connections_pricing" in query:
|
|
return None
|
|
if "FROM internet_connections_ip_ranges" in query:
|
|
return None
|
|
if "COUNT(*) AS total" in query and "FROM internet_connections_ip_addresses" in query:
|
|
return {"total": 0}
|
|
if "FROM internet_connections_ip_addresses" in query and "WHERE ip_address = %s" in query:
|
|
return None
|
|
return None
|
|
|
|
def fake_execute_query(query, params=None):
|
|
if "FROM internet_connections_connections" in query:
|
|
return []
|
|
if "FROM internet_connections_ip_ranges" in query:
|
|
return []
|
|
return []
|
|
|
|
def fake_execute_insert(query, params=None):
|
|
if "INSERT INTO internet_connections_connections" in query:
|
|
created_connections.append(params)
|
|
return 501
|
|
if "INSERT INTO internet_connections_ip_ranges" in query:
|
|
created_ranges.append(params)
|
|
return 601
|
|
return 1
|
|
|
|
def fake_execute_update(query, params=None):
|
|
if "INSERT INTO internet_connections_ip_addresses" in query:
|
|
ensured_ranges.append(params[0])
|
|
return 1
|
|
|
|
monkeypatch.setattr(supplier_module, "_load_extraction_lines", fake_load_lines)
|
|
monkeypatch.setattr(supplier_module, "_load_active_customers_for_matching", fake_load_customers)
|
|
monkeypatch.setattr(supplier_module, "execute_query", fake_execute_query)
|
|
monkeypatch.setattr(supplier_module, "execute_query_single", fake_execute_query_single)
|
|
monkeypatch.setattr(supplier_module, "execute_insert", fake_execute_insert)
|
|
monkeypatch.setattr(supplier_module, "execute_update", fake_execute_update)
|
|
|
|
result = supplier_module._sync_globalconnect_extraction_to_internet(extraction)
|
|
|
|
assert result["skipped"] is False
|
|
assert result["connections_synced"] == 1
|
|
assert result["connections_synced"] == 1
|
|
assert created_connections
|
|
assert created_ranges
|
|
assert ensured_ranges
|
|
assert created_connections[0][0] == "Malerfirmaet Gert Jensen ApS"
|
|
assert created_connections[0][9] == 100
|
|
assert created_connections[0][10] == 100
|
|
assert created_connections[0][11] == 100
|
|
assert created_connections[0][13] == "dedicated"
|
|
assert created_connections[0][14] == "other"
|
|
assert created_ranges[0][2] == "152.115.84.232/29"
|
|
|
|
|
|
def test_sync_globalconnect_infers_dsl_kbps_speed(monkeypatch):
|
|
created_connections = []
|
|
|
|
extraction = {
|
|
"extraction_id": 175,
|
|
"vendor_name": "GlobalConnect A/S",
|
|
"document_id": "3016392",
|
|
"document_date": "2026-01-01",
|
|
"llm_response_json": {"template": "dk.globalconnect"},
|
|
}
|
|
lines = [
|
|
{
|
|
"description": "20480/2048 Kbps ADSL forbindelse",
|
|
"provider_reference": "DSL-EB680288",
|
|
"circuit_id": "DSL-EB680288",
|
|
"line_total": 420.0,
|
|
"unit_price": 140.0,
|
|
"quantity": 3,
|
|
"end_customer_name": "Malerfirmaet Gert Jensen ApS",
|
|
"service_address": "Metalbuen 26, 2750 Ballerup",
|
|
}
|
|
]
|
|
|
|
monkeypatch.setattr(supplier_module, "_load_extraction_lines", lambda _: lines)
|
|
monkeypatch.setattr(
|
|
supplier_module,
|
|
"_load_active_customers_for_matching",
|
|
lambda: [{"id": 322, "name": "Malerfirmaet Gert Jensen ApS", "address": "Metalbuen 26", "postal_code": "2750", "city": "Ballerup"}],
|
|
)
|
|
monkeypatch.setattr(supplier_module, "execute_query", lambda query, params=None: [])
|
|
|
|
def fake_execute_query_single(query, params=None):
|
|
if "FROM internet_connections_ip_addresses" in query:
|
|
return {"total": 0}
|
|
return None
|
|
|
|
monkeypatch.setattr(supplier_module, "execute_query_single", fake_execute_query_single)
|
|
|
|
def fake_execute_insert(query, params=None):
|
|
if "INSERT INTO internet_connections_connections" in query:
|
|
created_connections.append(params)
|
|
return 700
|
|
return 1
|
|
|
|
monkeypatch.setattr(supplier_module, "execute_insert", fake_execute_insert)
|
|
monkeypatch.setattr(supplier_module, "execute_update", lambda query, params=None: 1)
|
|
|
|
result = supplier_module._sync_globalconnect_extraction_to_internet(extraction)
|
|
|
|
assert result["connections_synced"] == 1
|
|
assert created_connections
|
|
assert created_connections[0][9] == 20
|
|
assert created_connections[0][10] == 2
|
|
assert created_connections[0][11] == 20
|
|
|
|
|
|
def test_sync_globalconnect_marks_uncertain_connection_pending(monkeypatch):
|
|
extraction = {
|
|
"extraction_id": 176,
|
|
"vendor_name": "GlobalConnect A/S",
|
|
"document_id": "3018657",
|
|
"document_date": "2026-01-01",
|
|
"llm_response_json": {"template": "dk.globalconnect"},
|
|
}
|
|
lines = [
|
|
{
|
|
"description": "1 Gbps fiberforbindelse",
|
|
"provider_reference": "NKA020902",
|
|
"circuit_id": "NKA020902",
|
|
"line_total": 5417.4,
|
|
"unit_price": 1805.8,
|
|
"quantity": 3,
|
|
"end_customer_name": None,
|
|
"service_address": None,
|
|
}
|
|
]
|
|
|
|
monkeypatch.setattr(supplier_module, "_load_extraction_lines", lambda _: lines)
|
|
monkeypatch.setattr(supplier_module, "_load_active_customers_for_matching", lambda: [])
|
|
monkeypatch.setattr(supplier_module, "execute_query", lambda query, params=None: [])
|
|
|
|
result = supplier_module._sync_globalconnect_extraction_to_internet(extraction)
|
|
|
|
assert result["connections_synced"] == 0
|
|
assert result["skipped_connection_lines"] == 1
|
|
assert result["verification"]["requires_manual_review"] is True
|
|
assert result["skipped_items"][0]["reason"] == "Mangler serviceadresse"
|
|
|
|
|
|
def test_upsert_globalconnect_connection_requires_service_address(monkeypatch):
|
|
monkeypatch.setattr(supplier_module, "execute_query", lambda query, params=None: [])
|
|
|
|
connection_id = supplier_module._upsert_globalconnect_connection(
|
|
reference="NKA020902",
|
|
lines=[{
|
|
"description": "1 Gbps fiberforbindelse",
|
|
"provider_reference": "NKA020902",
|
|
"circuit_id": "NKA020902",
|
|
"line_total": 5417.4,
|
|
"unit_price": 1805.8,
|
|
"quantity": 3,
|
|
"end_customer_name": None,
|
|
"service_address": None,
|
|
}],
|
|
invoice_date="2026-01-01",
|
|
invoice_number="3018657",
|
|
customers=[],
|
|
)
|
|
|
|
assert connection_id is None
|
|
|
|
|
|
def test_sync_globalconnect_assigns_shared_bmc_value_model(monkeypatch):
|
|
created_connections = []
|
|
|
|
extraction = {
|
|
"extraction_id": 176,
|
|
"vendor_name": "GlobalConnect A/S",
|
|
"document_id": "3018657",
|
|
"document_date": "2026-01-01",
|
|
"llm_response_json": {"template": "dk.globalconnect"},
|
|
}
|
|
lines = [
|
|
{
|
|
"description": "IPv4 IP-adresser",
|
|
"provider_reference": "NKA008225",
|
|
"circuit_id": "NKA008225",
|
|
"ip_address": "152.115.57.96/27",
|
|
"line_total": 768.0,
|
|
"unit_price": 256.0,
|
|
"quantity": 3,
|
|
}
|
|
]
|
|
|
|
monkeypatch.setattr(supplier_module, "_load_extraction_lines", lambda _: lines)
|
|
monkeypatch.setattr(supplier_module, "_load_active_customers_for_matching", lambda: [])
|
|
monkeypatch.setattr(supplier_module, "_resolve_internal_bmc_customer", lambda: {"id": 1662, "name": "BMC Networks"})
|
|
monkeypatch.setattr(supplier_module, "execute_query", lambda query, params=None: [])
|
|
|
|
def fake_execute_query_single(query, params=None):
|
|
if "FROM internet_connections_ip_addresses" in query:
|
|
return {"total": 0}
|
|
return None
|
|
|
|
monkeypatch.setattr(supplier_module, "execute_query_single", fake_execute_query_single)
|
|
|
|
def fake_execute_insert(query, params=None):
|
|
if "INSERT INTO internet_connections_connections" in query:
|
|
created_connections.append(params)
|
|
return 800
|
|
return 1
|
|
|
|
monkeypatch.setattr(supplier_module, "execute_insert", fake_execute_insert)
|
|
monkeypatch.setattr(supplier_module, "execute_update", lambda query, params=None: 1)
|
|
|
|
result = supplier_module._sync_globalconnect_extraction_to_internet(extraction)
|
|
|
|
assert result["connections_synced"] == 0
|
|
assert result["ip_ranges_synced"] == 0
|
|
assert result["skipped_orphan_ip_ranges"] == 1
|
|
assert created_connections == []
|
|
|
|
|
|
def test_upsert_globalconnect_connection_assigns_delefiber_for_internal_shared_owner(monkeypatch):
|
|
created_connections = []
|
|
line = {
|
|
"description": "1 Gbps fiberforbindelse MPLS VPN",
|
|
"provider_reference": "NKA020900",
|
|
"circuit_id": "NKA020900",
|
|
"line_total": 4950.0,
|
|
"unit_price": 1650.0,
|
|
"quantity": 3,
|
|
"service_address": "Rydagervej 27, 2620 Albertslund",
|
|
"end_customer_name": "",
|
|
}
|
|
|
|
monkeypatch.setattr(supplier_module, "execute_query", lambda query, params=None: [])
|
|
monkeypatch.setattr(supplier_module, "_resolve_internal_bmc_customer", lambda: {"id": 1662, "name": "BMC Networks"})
|
|
monkeypatch.setattr(supplier_module, "_ensure_connection_pricing_entry", lambda **kwargs: None)
|
|
monkeypatch.setattr(supplier_module, "_append_connection_history", lambda *args, **kwargs: None)
|
|
|
|
def fake_execute_insert(query, params=None):
|
|
if "INSERT INTO internet_connections_connections" in query:
|
|
created_connections.append(params)
|
|
return 901
|
|
return 1
|
|
|
|
monkeypatch.setattr(supplier_module, "execute_insert", fake_execute_insert)
|
|
|
|
connection_id = supplier_module._upsert_globalconnect_connection(
|
|
reference="NKA020900",
|
|
lines=[line],
|
|
invoice_date="2026-01-01",
|
|
invoice_number="3018657",
|
|
customers=[],
|
|
)
|
|
|
|
assert connection_id == 901
|
|
assert created_connections
|
|
assert created_connections[0][2] == 1662
|
|
assert created_connections[0][-3] == "shared"
|
|
assert created_connections[0][-2] == "delefiber"
|
|
|
|
|
|
def test_sync_globalconnect_attaches_ip_range_to_existing_connection(monkeypatch):
|
|
created_ranges = []
|
|
|
|
extraction = {
|
|
"extraction_id": 176,
|
|
"vendor_name": "GlobalConnect A/S",
|
|
"document_id": "3018657",
|
|
"document_date": "2026-01-01",
|
|
"llm_response_json": {"template": "dk.globalconnect"},
|
|
}
|
|
lines = [
|
|
{
|
|
"description": "IPv4 IP-adresser",
|
|
"provider_reference": "NKA008225",
|
|
"circuit_id": "NKA008225",
|
|
"ip_address": "152.115.57.96/27",
|
|
"line_total": 768.0,
|
|
"unit_price": 256.0,
|
|
"quantity": 3,
|
|
"service_address": "Metalbuen 26, 2750 Ballerup",
|
|
}
|
|
]
|
|
|
|
monkeypatch.setattr(supplier_module, "_load_extraction_lines", lambda _: lines)
|
|
monkeypatch.setattr(supplier_module, "_load_active_customers_for_matching", lambda: [])
|
|
monkeypatch.setattr(
|
|
supplier_module,
|
|
"execute_query",
|
|
lambda query, params=None: [{"id": 16, "address": "Metalbuen 26, 2750 Ballerup"}] if "FROM internet_connections_connections" in query else [],
|
|
)
|
|
|
|
def fake_execute_query_single(query, params=None):
|
|
if "FROM internet_connections_ip_ranges" in query:
|
|
return None
|
|
if "FROM internet_connections_ip_addresses" in query:
|
|
return {"total": 0}
|
|
return None
|
|
|
|
monkeypatch.setattr(supplier_module, "execute_query_single", fake_execute_query_single)
|
|
monkeypatch.setattr(supplier_module, "execute_insert", lambda query, params=None: 601 if "INSERT INTO internet_connections_ip_ranges" in query else 1)
|
|
|
|
def fake_execute_update(query, params=None):
|
|
return 1
|
|
|
|
monkeypatch.setattr(supplier_module, "execute_update", fake_execute_update)
|
|
|
|
result = supplier_module._sync_globalconnect_extraction_to_internet(extraction)
|
|
|
|
assert result["connections_synced"] == 0
|
|
assert result["ip_ranges_synced"] == 1
|
|
assert result["skipped_orphan_ip_ranges"] == 0
|
|
assert result["line_audit"][0]["result"] == "linked_existing_connection"
|
|
|
|
|
|
def test_sync_globalconnect_normalizes_reference_without_dash(monkeypatch):
|
|
created_ranges = []
|
|
|
|
extraction = {
|
|
"extraction_id": 176,
|
|
"vendor_name": "GlobalConnect A/S",
|
|
"document_id": "3018657",
|
|
"document_date": "2026-01-01",
|
|
"llm_response_json": {"template": "dk.globalconnect"},
|
|
}
|
|
lines = [
|
|
{
|
|
"description": "IPv4 IP-adresser",
|
|
"provider_reference": "NKA008225",
|
|
"circuit_id": "NKA008225",
|
|
"ip_address": "152.115.57.96/27",
|
|
"line_total": 768.0,
|
|
"unit_price": 256.0,
|
|
"quantity": 3,
|
|
"service_address": "Metalbuen 26, 2750 Ballerup",
|
|
}
|
|
]
|
|
|
|
monkeypatch.setattr(supplier_module, "_load_extraction_lines", lambda _: lines)
|
|
monkeypatch.setattr(supplier_module, "_load_active_customers_for_matching", lambda: [])
|
|
monkeypatch.setattr(
|
|
supplier_module,
|
|
"execute_query",
|
|
lambda query, params=None: [{"id": 32, "address": "Metalbuen 26, 2750 Ballerup"}] if "FROM internet_connections_connections" in query else [],
|
|
)
|
|
|
|
def fake_execute_query_single(query, params=None):
|
|
if "FROM internet_connections_ip_ranges" in query:
|
|
return None
|
|
if "FROM internet_connections_ip_addresses" in query:
|
|
return {"total": 0}
|
|
return None
|
|
|
|
monkeypatch.setattr(supplier_module, "execute_query_single", fake_execute_query_single)
|
|
def fake_execute_insert(query, params=None):
|
|
if "INSERT INTO internet_connections_ip_ranges" in query:
|
|
created_ranges.append(params)
|
|
return 3
|
|
return 1
|
|
|
|
monkeypatch.setattr(supplier_module, "execute_insert", fake_execute_insert)
|
|
monkeypatch.setattr(supplier_module, "execute_update", lambda query, params=None: 1)
|
|
|
|
result = supplier_module._sync_globalconnect_extraction_to_internet(extraction)
|
|
|
|
assert result["ip_ranges_synced"] == 1
|
|
assert created_ranges
|
|
assert created_ranges[0][0] == 32
|
|
|
|
|
|
def test_sync_globalconnect_merges_duplicate_connections(monkeypatch):
|
|
updates = []
|
|
|
|
extraction = {
|
|
"extraction_id": 176,
|
|
"vendor_name": "GlobalConnect A/S",
|
|
"document_id": "3018657",
|
|
"document_date": "2026-01-01",
|
|
"llm_response_json": {"template": "dk.globalconnect"},
|
|
}
|
|
lines = [
|
|
{
|
|
"description": "100 Mbps fiberforbindelse",
|
|
"provider_reference": "NKA008225",
|
|
"circuit_id": "NKA008225",
|
|
"line_total": 768.0,
|
|
"unit_price": 256.0,
|
|
"quantity": 3,
|
|
"service_address": "Metalbuen 26, 2750 Ballerup",
|
|
}
|
|
]
|
|
|
|
monkeypatch.setattr(supplier_module, "_load_extraction_lines", lambda _: lines)
|
|
monkeypatch.setattr(supplier_module, "_load_active_customers_for_matching", lambda: [])
|
|
|
|
def fake_execute_query(query, params=None):
|
|
if "FROM internet_connections_connections" in query:
|
|
return [{"id": 16, "customer_id": None, "address": None}, {"id": 32, "customer_id": None, "address": None}]
|
|
if "FROM internet_connections_ip_ranges" in query:
|
|
return []
|
|
return []
|
|
|
|
def fake_execute_query_single(query, params=None):
|
|
if "FROM internet_connections_ip_ranges" in query:
|
|
return None
|
|
if "FROM internet_connections_ip_addresses" in query:
|
|
return {"total": 0}
|
|
return None
|
|
|
|
monkeypatch.setattr(supplier_module, "execute_query", fake_execute_query)
|
|
monkeypatch.setattr(supplier_module, "execute_query_single", fake_execute_query_single)
|
|
monkeypatch.setattr(supplier_module, "execute_insert", lambda query, params=None: 3)
|
|
monkeypatch.setattr(supplier_module, "_ensure_internet_change_case", lambda **kwargs: 99)
|
|
monkeypatch.setattr(supplier_module, "_ensure_connection_pricing_entry", lambda **kwargs: None)
|
|
|
|
def fake_execute_update(query, params=None):
|
|
updates.append((query, params))
|
|
return 1
|
|
|
|
monkeypatch.setattr(supplier_module, "execute_update", fake_execute_update)
|
|
|
|
result = supplier_module._sync_globalconnect_extraction_to_internet(extraction)
|
|
|
|
assert result["connections_synced"] == 1
|
|
assert any(
|
|
"UPDATE internet_connections_ip_ranges" in query and params[0] == 16 and params[1] == 32
|
|
for query, params in updates
|
|
)
|
|
assert any(
|
|
"UPDATE internet_connections_connections" in query and params[1] == 32
|
|
for query, params in updates
|
|
)
|
|
|
|
|
|
def test_sync_globalconnect_skips_reference_when_address_conflicts(monkeypatch):
|
|
extraction = {
|
|
"extraction_id": 176,
|
|
"vendor_name": "GlobalConnect A/S",
|
|
"document_id": "3018657",
|
|
"document_date": "2026-01-01",
|
|
"llm_response_json": {"template": "dk.globalconnect"},
|
|
}
|
|
lines = [
|
|
{
|
|
"description": "100 Mbps fiberforbindelse",
|
|
"provider_reference": "NKA008225",
|
|
"circuit_id": "NKA008225",
|
|
"line_total": 768.0,
|
|
"unit_price": 256.0,
|
|
"quantity": 3,
|
|
"service_address": "Metalbuen 26, 2750 Ballerup",
|
|
}
|
|
]
|
|
|
|
monkeypatch.setattr(supplier_module, "_load_extraction_lines", lambda _: lines)
|
|
monkeypatch.setattr(supplier_module, "_load_active_customers_for_matching", lambda: [])
|
|
monkeypatch.setattr(
|
|
supplier_module,
|
|
"execute_query",
|
|
lambda query, params=None: [{"id": 16, "address": "Andenvej 99, 2100 København Ø"}] if "FROM internet_connections_connections" in query else [],
|
|
)
|
|
|
|
result = supplier_module._sync_globalconnect_extraction_to_internet(extraction)
|
|
|
|
assert result["connections_synced"] == 0
|
|
assert result["verification"]["requires_manual_review"] is True
|
|
assert "anden adresse" in result["skipped_items"][0]["reason"].lower()
|
|
|
|
|
|
def test_sync_globalconnect_skips_ip_range_when_connection_reference_has_other_service_address(monkeypatch):
|
|
extraction = {
|
|
"extraction_id": 180,
|
|
"vendor_name": "GlobalConnect A/S",
|
|
"document_id": "3018657",
|
|
"document_date": "2026-01-01",
|
|
"llm_response_json": {"template": "dk.globalconnect"},
|
|
}
|
|
lines = [
|
|
{
|
|
"description": "1 Gbps fiberforbindelse MPLS VPN",
|
|
"provider_reference": "NKA020900",
|
|
"circuit_id": "NKA020900",
|
|
"line_total": 4950.0,
|
|
"unit_price": 1650.0,
|
|
"quantity": 3,
|
|
"service_address": "Rydagervej 27, 2620 Albertslund",
|
|
},
|
|
{
|
|
"description": "IPv4 IP-adresser",
|
|
"provider_reference": "NKA-020900",
|
|
"circuit_id": "NKA-020900",
|
|
"ip_address": "87.116.1.200/29",
|
|
"line_total": 384.0,
|
|
"unit_price": 128.0,
|
|
"quantity": 3,
|
|
"service_address": "Tobaksvejen 25, 2860 Søborg",
|
|
},
|
|
]
|
|
|
|
monkeypatch.setattr(supplier_module, "_load_extraction_lines", lambda _: lines)
|
|
monkeypatch.setattr(supplier_module, "_load_active_customers_for_matching", lambda: [])
|
|
monkeypatch.setattr(supplier_module, "_ensure_connection_pricing_entry", lambda **kwargs: None)
|
|
monkeypatch.setattr(supplier_module, "_append_connection_history", lambda *args, **kwargs: None)
|
|
monkeypatch.setattr(supplier_module, "_ensure_internet_change_case", lambda **kwargs: None)
|
|
|
|
def fake_execute_query(query, params=None):
|
|
if "FROM internet_connections_connections" in query:
|
|
if "regexp_replace(UPPER(COALESCE(circuit_number, ''))" in query:
|
|
return []
|
|
return []
|
|
if "FROM internet_connections_ip_ranges" in query:
|
|
return []
|
|
return []
|
|
|
|
def fake_execute_query_single(query, params=None):
|
|
if "FROM customers" in query:
|
|
return None
|
|
if "FROM internet_connections_connections" in query and "WHERE id = %s" in query:
|
|
return {
|
|
"address": "Rydagervej 27, 2620 Albertslund",
|
|
"allocation_model": "dedicated",
|
|
}
|
|
if "FROM internet_connections_ip_ranges" in query:
|
|
return None
|
|
if "FROM internet_connections_ip_addresses" in query:
|
|
return {"total": 0}
|
|
return None
|
|
|
|
created_connections = []
|
|
|
|
def fake_execute_insert(query, params=None):
|
|
if "INSERT INTO internet_connections_connections" in query:
|
|
created_connections.append(params)
|
|
return 96
|
|
if "INSERT INTO internet_connections_ip_ranges" in query:
|
|
raise AssertionError("IP-range should not be created when service address conflicts")
|
|
return 1
|
|
|
|
monkeypatch.setattr(supplier_module, "execute_query", fake_execute_query)
|
|
monkeypatch.setattr(supplier_module, "execute_query_single", fake_execute_query_single)
|
|
monkeypatch.setattr(supplier_module, "execute_insert", fake_execute_insert)
|
|
monkeypatch.setattr(supplier_module, "execute_update", lambda query, params=None: 1)
|
|
|
|
result = supplier_module._sync_globalconnect_extraction_to_internet(extraction)
|
|
|
|
assert result["connections_synced"] == 1
|
|
assert result["ip_ranges_synced"] == 0
|
|
assert result["skipped_orphan_ip_ranges"] == 1
|
|
assert created_connections
|
|
skipped_ip_entries = [entry for entry in result["line_audit"] if entry["classification"] == "ip_range"]
|
|
assert skipped_ip_entries
|
|
assert skipped_ip_entries[0]["status"] == "skipped"
|
|
assert "ingen forbindelse fundet" in (skipped_ip_entries[0]["reason"] or "").lower()
|
|
|
|
|
|
def test_upsert_globalconnect_connection_logs_changes_and_creates_case(monkeypatch):
|
|
history_calls = []
|
|
case_calls = []
|
|
updates = []
|
|
|
|
customer = {
|
|
"id": 322,
|
|
"name": "Malerfirmaet Gert Jensen ApS",
|
|
"address": "Metalbuen 26",
|
|
"postal_code": "2750",
|
|
"city": "Ballerup",
|
|
}
|
|
line = {
|
|
"description": "200 Mbps fiberforbindelse",
|
|
"provider_reference": "NKA008214",
|
|
"circuit_id": "NKA008214",
|
|
"line_total": 360.0,
|
|
"unit_price": 120.0,
|
|
"quantity": 3,
|
|
"end_customer_name": "Malerfirmaet Gert Jensen ApS",
|
|
"service_address": "Metalbuen 26, 2750 Ballerup",
|
|
}
|
|
|
|
def fake_execute_query(query, params=None):
|
|
if "FROM internet_connections_connections" in query:
|
|
return [
|
|
{
|
|
"id": 16,
|
|
"customer_id": 322,
|
|
"address": "Metalbuen 26, 2750 Ballerup",
|
|
"monthly_cost": Decimal("100.00"),
|
|
"technology": "Fiber",
|
|
"connection_type": "fiber",
|
|
"circuit_number": "NKA008214",
|
|
"speed_mbps": 100,
|
|
"download_mbps": 100,
|
|
"upload_mbps": 100,
|
|
"status": "active",
|
|
"allocation_model": "dedicated",
|
|
"value_type": "other",
|
|
"value_label": None,
|
|
}
|
|
]
|
|
return []
|
|
|
|
monkeypatch.setattr(supplier_module, "execute_query", fake_execute_query)
|
|
monkeypatch.setattr(supplier_module, "execute_update", lambda query, params=None: updates.append((query, params)) or 1)
|
|
monkeypatch.setattr(supplier_module, "_append_connection_history", lambda *args: history_calls.append(args))
|
|
monkeypatch.setattr(supplier_module, "_ensure_internet_change_case", lambda **kwargs: case_calls.append(kwargs) or 91)
|
|
monkeypatch.setattr(supplier_module, "_ensure_connection_pricing_entry", lambda **kwargs: None)
|
|
|
|
connection_id = supplier_module._upsert_globalconnect_connection(
|
|
reference="NKA008214",
|
|
lines=[line],
|
|
invoice_date="2026-01-01",
|
|
invoice_number="3018657",
|
|
customers=[customer],
|
|
)
|
|
|
|
assert connection_id == 16
|
|
assert updates
|
|
assert history_calls
|
|
assert history_calls[0][1] == "supplier_invoice_sync_changed"
|
|
assert history_calls[0][3]["changes"]["monthly_cost"] == {"from": "100.00", "to": "120.00"}
|
|
assert history_calls[0][3]["changes"]["speed_mbps"] == {"from": "100", "to": "200"}
|
|
assert case_calls
|
|
assert case_calls[0]["connection_id"] == 16
|
|
assert case_calls[0]["changes"]["download_mbps"] == {"from": "100", "to": "200"}
|
|
|
|
|
|
def test_upsert_globalconnect_ip_range_logs_changes_and_creates_case(monkeypatch):
|
|
history_calls = []
|
|
case_calls = []
|
|
customer = {
|
|
"id": 322,
|
|
"name": "Malerfirmaet Gert Jensen ApS",
|
|
"address": "Metalbuen 26",
|
|
"postal_code": "2750",
|
|
"city": "Ballerup",
|
|
}
|
|
line = {
|
|
"description": "IPv4 IP-adresser",
|
|
"provider_reference": "NKA008214",
|
|
"circuit_id": "NKA008214",
|
|
"contract_number": "GC-NEW",
|
|
"ip_address": "152.115.84.232/29",
|
|
"line_total": 240.0,
|
|
"unit_price": 80.0,
|
|
"quantity": 3,
|
|
"end_customer_name": "Malerfirmaet Gert Jensen ApS",
|
|
"service_address": "Metalbuen 26, 2750 Ballerup",
|
|
}
|
|
|
|
def fake_execute_query_single(query, params=None):
|
|
if "FROM internet_connections_ip_ranges" in query:
|
|
return {
|
|
"id": 88,
|
|
"provider_reference": "NKA008214",
|
|
"contract_number": "GC-OLD",
|
|
"customer_id": None,
|
|
"service_address": "Gammel adresse 1, 2000 Frederiksberg",
|
|
"monthly_cost": Decimal("64.00"),
|
|
}
|
|
if "FROM internet_connections_ip_addresses" in query:
|
|
return {"total": 6}
|
|
return None
|
|
|
|
monkeypatch.setattr(supplier_module, "execute_query", lambda query, params=None: [])
|
|
monkeypatch.setattr(supplier_module, "execute_query_single", fake_execute_query_single)
|
|
monkeypatch.setattr(supplier_module, "execute_update", lambda query, params=None: 1)
|
|
monkeypatch.setattr(supplier_module, "_append_connection_history", lambda *args: history_calls.append(args))
|
|
monkeypatch.setattr(supplier_module, "_ensure_internet_change_case", lambda **kwargs: case_calls.append(kwargs) or 92)
|
|
monkeypatch.setattr(supplier_module, "_ensure_ip_addresses_for_range", lambda range_id, cidr: 6)
|
|
monkeypatch.setattr(supplier_module, "_load_active_customers_for_matching", lambda: [customer])
|
|
|
|
range_id = supplier_module._upsert_globalconnect_ip_range(16, line, "3018657")
|
|
|
|
assert range_id == 88
|
|
assert history_calls
|
|
assert history_calls[0][1] == "supplier_invoice_ip_range_changed"
|
|
assert history_calls[0][3]["changes"]["contract_number"] == {"from": "GC-OLD", "to": "GC-NEW"}
|
|
assert history_calls[0][3]["changes"]["monthly_cost"] == {"from": "64.00", "to": "80.00"}
|
|
assert case_calls
|
|
assert case_calls[0]["reference"] == "NKA008214"
|
|
assert case_calls[0]["changes"]["service_address"]["to"] == "Metalbuen 26, 2750 Ballerup"
|
|
|
|
|
|
def test_supplier_sync_skips_ip_addresses_that_already_exist(monkeypatch):
|
|
inserted = []
|
|
|
|
def fake_execute_query_single(query, params=None):
|
|
if "COUNT(*) AS total" in query and "internet_connections_ip_addresses" in query:
|
|
return {"total": 0}
|
|
if "FROM internet_connections_ip_addresses" in query and "WHERE ip_address = %s" in query:
|
|
if params[0] == "152.115.84.233":
|
|
return {"id": 91}
|
|
return None
|
|
return None
|
|
|
|
def fake_execute_update(query, params=None):
|
|
if "INSERT INTO internet_connections_ip_addresses" in query:
|
|
inserted.append(params[1])
|
|
return 1
|
|
|
|
monkeypatch.setattr(supplier_module, "execute_query_single", fake_execute_query_single)
|
|
monkeypatch.setattr(supplier_module, "execute_update", fake_execute_update)
|
|
|
|
created = supplier_module._ensure_ip_addresses_for_range(601, "152.115.84.232/30")
|
|
|
|
assert created == 1
|
|
assert inserted == ["152.115.84.234"]
|
|
|
|
|
|
def test_append_amount_validation_case_note_creates_system_comment(monkeypatch):
|
|
comments = []
|
|
|
|
def fake_execute_query_single(query, params=None):
|
|
if "FROM sag_kommentarer" in query:
|
|
return None
|
|
return None
|
|
|
|
def fake_execute_update(query, params=None):
|
|
if "INSERT INTO sag_kommentarer" in query:
|
|
comments.append(params)
|
|
return 1
|
|
|
|
monkeypatch.setattr(supplier_module, "execute_query_single", fake_execute_query_single)
|
|
monkeypatch.setattr(supplier_module, "execute_update", fake_execute_update)
|
|
|
|
supplier_module._append_amount_validation_case_note(
|
|
sag_id=91,
|
|
invoice_id=17,
|
|
invoice_number="3018657",
|
|
validation_details={
|
|
"line_sum": 600.0,
|
|
"subtotal": 800.0,
|
|
"difference": 200.0,
|
|
"vat_amount": 200.0,
|
|
"vat_expected": 200.0,
|
|
"vat_difference": 0.0,
|
|
},
|
|
validation_warning="Varelinjer sum (600.00) passer ikke med subtotal (800.00)",
|
|
vat_warning=None,
|
|
file_id=176,
|
|
)
|
|
|
|
assert comments
|
|
assert comments[0][0] == 91
|
|
assert "Subtotal-advarsel" in comments[0][2]
|
|
assert "Afvigelse: 200.0" in comments[0][2]
|