release: v2.8.8 fix economic permissions and order validation
This commit is contained in:
parent
3e8e5ba1cf
commit
87932f8e16
17
MDfile/RELEASE_NOTES_v2.8.8.md
Normal file
17
MDfile/RELEASE_NOTES_v2.8.8.md
Normal file
@ -0,0 +1,17 @@
|
||||
# BMC Hub v2.8.8
|
||||
|
||||
## Rettelse af adgang til e-conomic-varekataloget
|
||||
|
||||
- Tildeler de nye e-conomic-rettigheder til den eksisterende `Administrators`-gruppe.
|
||||
- Retter fejlen `Missing required permission: economic.catalog.view` for almindelige administratorer.
|
||||
- Andre grupper og brugere får ikke nye rettigheder automatisk.
|
||||
|
||||
## Ordreeksport
|
||||
|
||||
- Stopper eksporten før afsendelse, hvis et varenummer ikke findes i e-conomic.
|
||||
- Viser de manglende varenumre og sender ikke længere prislinjer uden den produktreference, som e-conomic kræver.
|
||||
|
||||
## Installation
|
||||
|
||||
- Kør migration `244_economic_permissions_backfill.sql` efter migration 242 og 243.
|
||||
- Migrationen er idempotent og ændrer kun gruppens koblinger til eksisterende rettigheder.
|
||||
@ -44,6 +44,21 @@ def _economic_error_message(status: int, response_text: str) -> str:
|
||||
return f"e-conomic afviste ordren ({status})" + (f": {detail}" if detail else "")
|
||||
|
||||
|
||||
def _require_valid_product_numbers(product_numbers: set[str], valid_product_numbers: set[str]) -> List[str]:
|
||||
"""Reject priced lines before POST when e-conomic cannot resolve their product."""
|
||||
missing = sorted(product_numbers - valid_product_numbers)
|
||||
if missing:
|
||||
raise HTTPException(
|
||||
status_code=409,
|
||||
detail=(
|
||||
"Ordren blev ikke sendt. Følgende varenumre findes ikke i e-conomic: "
|
||||
+ ", ".join(missing)
|
||||
+ ". Knyt eller opret varerne under Varer og e-conomic, og prøv igen."
|
||||
),
|
||||
)
|
||||
return missing
|
||||
|
||||
|
||||
class OrdreEconomicExportService:
|
||||
"""e-conomic export service for global ordre page."""
|
||||
|
||||
@ -224,10 +239,7 @@ class OrdreEconomicExportService:
|
||||
if product_response.status == 200:
|
||||
valid_product_numbers.add(product_number)
|
||||
elif product_response.status == 404:
|
||||
logger.warning(
|
||||
"e-conomic product %s does not exist; exporting matching lines as free text",
|
||||
product_number,
|
||||
)
|
||||
logger.warning("e-conomic product %s does not exist", product_number)
|
||||
else:
|
||||
product_text = await product_response.text()
|
||||
raise HTTPException(
|
||||
@ -235,11 +247,7 @@ class OrdreEconomicExportService:
|
||||
detail=_economic_error_message(product_response.status, product_text),
|
||||
)
|
||||
|
||||
skipped_product_numbers = sorted(product_numbers - valid_product_numbers)
|
||||
for line in economic_lines:
|
||||
product_number = str(line.get("product", {}).get("productNumber") or "").strip()
|
||||
if product_number and product_number not in valid_product_numbers:
|
||||
line.pop("product", None)
|
||||
missing_product_numbers = _require_valid_product_numbers(product_numbers, valid_product_numbers)
|
||||
|
||||
customer_layout = economic_customer.get("layout") or {}
|
||||
resolved_layout_number = customer_layout.get("layoutNumber") or self.default_layout
|
||||
@ -278,7 +286,8 @@ class OrdreEconomicExportService:
|
||||
"read_only": self.read_only,
|
||||
"dry_run": self.dry_run,
|
||||
"user_id": user_id,
|
||||
"skipped_product_numbers": skipped_product_numbers,
|
||||
"skipped_product_numbers": missing_product_numbers,
|
||||
"missing_product_numbers": missing_product_numbers,
|
||||
"payload": payload,
|
||||
},
|
||||
}
|
||||
@ -314,7 +323,8 @@ class OrdreEconomicExportService:
|
||||
"customer_name": customer.get("name"),
|
||||
"selected_line_count": len(selected_lines),
|
||||
"user_id": user_id,
|
||||
"skipped_product_numbers": skipped_product_numbers,
|
||||
"skipped_product_numbers": missing_product_numbers,
|
||||
"missing_product_numbers": missing_product_numbers,
|
||||
"economic_response": export_result,
|
||||
},
|
||||
}
|
||||
|
||||
14
migrations/244_economic_permissions_backfill.sql
Normal file
14
migrations/244_economic_permissions_backfill.sql
Normal file
@ -0,0 +1,14 @@
|
||||
-- Preserve administrator access after adding the e-conomic catalog permissions.
|
||||
-- Migration 002 grants all permissions known at install time, so permissions
|
||||
-- introduced later must also be assigned to the Administrators group.
|
||||
BEGIN;
|
||||
|
||||
INSERT INTO group_permissions (group_id, permission_id)
|
||||
SELECT g.id, p.id
|
||||
FROM groups g
|
||||
CROSS JOIN permissions p
|
||||
WHERE g.name = 'Administrators'
|
||||
AND p.category = 'economic'
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
COMMIT;
|
||||
@ -47,3 +47,22 @@ def test_economic_validation_error_is_exposed_without_developer_metadata():
|
||||
assert "paymentTerms" in message
|
||||
assert "Required" in message
|
||||
assert "internal" not in message
|
||||
|
||||
|
||||
def test_order_export_blocks_priced_line_when_product_does_not_exist():
|
||||
from fastapi import HTTPException
|
||||
from app.modules.orders.backend.economic_export import _require_valid_product_numbers
|
||||
|
||||
try:
|
||||
_require_valid_product_numbers({"1000", "UKENDT"}, {"1000"})
|
||||
assert False, "missing product must block the export before POST"
|
||||
except HTTPException as exc:
|
||||
assert exc.status_code == 409
|
||||
assert "UKENDT" in exc.detail
|
||||
assert "Ordren blev ikke sendt" in exc.detail
|
||||
|
||||
|
||||
def test_order_export_accepts_only_verified_products():
|
||||
from app.modules.orders.backend.economic_export import _require_valid_product_numbers
|
||||
|
||||
assert _require_valid_product_numbers({"1000"}, {"1000"}) == []
|
||||
|
||||
Loading…
Reference in New Issue
Block a user