fix(loyalty): show category column on card-detail for all 3 personas
The transaction-history table on the card-detail page rendered a
Category column only on the store frontend. Merchant and admin saw
five columns instead of six, even though the merchant report
prompted the audit (rewardflow.lu/merchants/loyalty/cards/6 vs
fashionhub.rewardflow.lu/store/.../cards/6).
Root cause was two layers:
- API: only store's GET /cards/{id}/transactions enriched
tx.category_names from tx.category_ids; merchant's and admin's
endpoints returned raw rows with category_names=null.
- Template: the shared partial's show_category_column flag was set
to true only on the store wrapper.
Backfill the same `category_service.validate_category_for_store`
lookup loop into merchant.py::get_card_transactions and
admin.py::get_merchant_card_transactions, accepting Request to read
request.state.language for localised category names. Add
`{% set show_category_column = true %}` to the merchant and admin
card-detail wrappers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,7 @@ Platform admin endpoints for:
|
||||
|
||||
import logging
|
||||
|
||||
from fastapi import APIRouter, Depends, Path, Query
|
||||
from fastapi import APIRouter, Depends, Path, Query, Request
|
||||
from pydantic import BaseModel, Field
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@@ -412,6 +412,7 @@ def get_merchant_card(
|
||||
response_model=TransactionListResponse,
|
||||
)
|
||||
def get_merchant_card_transactions(
|
||||
request: Request,
|
||||
merchant_id: int = Path(..., gt=0),
|
||||
card_id: int = Path(..., gt=0),
|
||||
skip: int = Query(0, ge=0),
|
||||
@@ -430,10 +431,26 @@ def get_merchant_card_transactions(
|
||||
db, card_id, skip=skip, limit=limit
|
||||
)
|
||||
|
||||
return TransactionListResponse(
|
||||
transactions=[TransactionResponse.model_validate(t) for t in transactions],
|
||||
total=total,
|
||||
)
|
||||
# Enrich category_names from category_ids (same as store + merchant routes
|
||||
# — keeps the transaction history aligned across personas).
|
||||
from app.modules.loyalty.services.category_service import category_service
|
||||
|
||||
lang = getattr(request.state, "language", "en") or "en"
|
||||
tx_responses = []
|
||||
for t in transactions:
|
||||
tx = TransactionResponse.model_validate(t)
|
||||
if t.category_ids and isinstance(t.category_ids, list):
|
||||
names = []
|
||||
for cid in t.category_ids:
|
||||
name = category_service.validate_category_for_store(
|
||||
db, cid, t.store_id or 0, lang=lang
|
||||
)
|
||||
if name:
|
||||
names.append(name)
|
||||
tx.category_names = names if names else None
|
||||
tx_responses.append(tx)
|
||||
|
||||
return TransactionListResponse(transactions=tx_responses, total=total)
|
||||
|
||||
|
||||
@router.get("/merchants/{merchant_id}/transactions", response_model=TransactionListResponse)
|
||||
|
||||
@@ -23,7 +23,7 @@ registration under /api/v1/merchants/loyalty/*).
|
||||
|
||||
import logging
|
||||
|
||||
from fastapi import APIRouter, Depends, Path, Query
|
||||
from fastapi import APIRouter, Depends, Path, Query, Request
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.deps import get_current_merchant_api, get_merchant_for_current_user
|
||||
@@ -256,6 +256,7 @@ def get_card_detail(
|
||||
|
||||
@router.get("/cards/{card_id}/transactions", response_model=TransactionListResponse)
|
||||
def get_card_transactions(
|
||||
request: Request,
|
||||
card_id: int = Path(..., gt=0),
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(50, ge=1, le=100),
|
||||
@@ -271,10 +272,26 @@ def get_card_transactions(
|
||||
db, card_id, skip=skip, limit=limit
|
||||
)
|
||||
|
||||
return TransactionListResponse(
|
||||
transactions=[TransactionResponse.model_validate(t) for t in transactions],
|
||||
total=total,
|
||||
)
|
||||
# Enrich category_names from category_ids (same as store route — keeps the
|
||||
# transaction history aligned across personas).
|
||||
from app.modules.loyalty.services.category_service import category_service
|
||||
|
||||
lang = getattr(request.state, "language", "en") or "en"
|
||||
tx_responses = []
|
||||
for t in transactions:
|
||||
tx = TransactionResponse.model_validate(t)
|
||||
if t.category_ids and isinstance(t.category_ids, list):
|
||||
names = []
|
||||
for cid in t.category_ids:
|
||||
name = category_service.validate_category_for_store(
|
||||
db, cid, t.store_id or 0, lang=lang
|
||||
)
|
||||
if name:
|
||||
names.append(name)
|
||||
tx.category_names = names if names else None
|
||||
tx_responses.append(tx)
|
||||
|
||||
return TransactionListResponse(transactions=tx_responses, total=total)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
{% set card_detail_api_prefix = '/admin/loyalty/merchants/' + merchant_id|string %}
|
||||
{% set card_detail_back_url = '/admin/loyalty/merchants/' + merchant_id|string + '/cards' %}
|
||||
{% set show_category_column = true %}
|
||||
{% include 'loyalty/shared/card-detail-view.html' %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
{% set card_detail_api_prefix = '/merchants/loyalty' %}
|
||||
{% set card_detail_back_url = '/merchants/loyalty/cards' %}
|
||||
{% set show_category_column = true %}
|
||||
{% include 'loyalty/shared/card-detail-view.html' %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user