fix: Include period-based lines and normalize product grouping
- Include lines with period fields even without keywords - Normalize product names to group similar lines - Improves monthly Hosting - AR2 visibility
This commit is contained in:
parent
9c6834b9f6
commit
501032efcd
@ -191,20 +191,24 @@ class SubscriptionMatrixService:
|
|||||||
product_number = line.get('product', {}).get('productNumber')
|
product_number = line.get('product', {}).get('productNumber')
|
||||||
product_name = line.get('product', {}).get('name') or line.get('description')
|
product_name = line.get('product', {}).get('name') or line.get('description')
|
||||||
line_description = (line.get('description') or product_name or "").lower()
|
line_description = (line.get('description') or product_name or "").lower()
|
||||||
# Only include lines that indicate a period or subscription
|
|
||||||
|
line_period = self._extract_period_from_text(line_description) or invoice_period
|
||||||
|
has_period = bool(line.get('period', {}).get('from') if line.get('period') else None) or bool(line_period)
|
||||||
|
|
||||||
|
# Only include lines that indicate a period or subscription or explicit period fields
|
||||||
if (
|
if (
|
||||||
"periode" not in line_description
|
"periode" not in line_description
|
||||||
and "abonnement" not in line_description
|
and "abonnement" not in line_description
|
||||||
and "periode" not in invoice_text
|
and "periode" not in invoice_text
|
||||||
and "abonnement" not in invoice_text
|
and "abonnement" not in invoice_text
|
||||||
|
and not has_period
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
line_period = self._extract_period_from_text(line_description) or invoice_period
|
|
||||||
|
|
||||||
if not product_number and not product_name:
|
if not product_number and not product_name:
|
||||||
logger.debug(f"Skipping line without product number: {line}")
|
logger.debug(f"Skipping line without product number: {line}")
|
||||||
continue
|
continue
|
||||||
product_key = product_number or (product_name or "").strip().lower()
|
product_key = product_number or self._normalize_product_key(product_name or "")
|
||||||
|
|
||||||
# Cache product name
|
# Cache product name
|
||||||
if product_key not in product_names:
|
if product_key not in product_names:
|
||||||
@ -355,6 +359,19 @@ class SubscriptionMatrixService:
|
|||||||
next_month = dt.replace(day=28) + timedelta(days=4)
|
next_month = dt.replace(day=28) + timedelta(days=4)
|
||||||
return next_month - timedelta(days=next_month.day)
|
return next_month - timedelta(days=next_month.day)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _normalize_product_key(name: str) -> str:
|
||||||
|
"""Normalize product names to keep similar lines on the same row."""
|
||||||
|
base = (name or "").lower().strip()
|
||||||
|
# Remove period phrases like "periode" and trailing date ranges
|
||||||
|
for token in ["periode", "abonnement"]:
|
||||||
|
if token in base:
|
||||||
|
base = base.split(token)[0].strip()
|
||||||
|
# Collapse multiple spaces
|
||||||
|
while " " in base:
|
||||||
|
base = base.replace(" ", " ")
|
||||||
|
return base or name.lower().strip()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _extract_period_from_text(text: str) -> Optional[datetime]:
|
def _extract_period_from_text(text: str) -> Optional[datetime]:
|
||||||
"""Extract month/year from invoice title/notes text (e.g., 'Periode May 2025')."""
|
"""Extract month/year from invoice title/notes text (e.g., 'Periode May 2025')."""
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user