test_price_calendar.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import pytest
  2. from datetime import date, timedelta
  3. from room_cal.pricing import CalPrice, PriceData
  4. from room_cal.pricing.calc import net_to_list
  5. from room_cal.pricing.price_calendar import _build_description
  6. from room_cal.discount import DiscountType
  7. # ── _build_description ────────────────────────────────────────────────────────
  8. def test_build_description_net_only():
  9. assert _build_description(PriceData(base=100, net=100)) == 'Net: $100'
  10. def test_build_description_base_equals_net_omits_base():
  11. result = _build_description(PriceData(base=100, net=100))
  12. assert 'Base:' not in result
  13. assert result == 'Net: $100'
  14. def test_build_description_base_differs_from_net():
  15. result = _build_description(PriceData(base=100, net=90))
  16. assert 'Net: $90' in result
  17. assert 'Base: $100' in result
  18. def test_build_description_flat_discount():
  19. prices = PriceData(base=100, net=90, discount=10, discount_type=DiscountType.FLAT, discount_value=10)
  20. result = _build_description(prices)
  21. assert 'Discount: $10' in result
  22. assert '%' not in result
  23. def test_build_description_percent_discount():
  24. prices = PriceData(base=100, net=90, discount=10, discount_type=DiscountType.PERCENT, discount_value=10)
  25. result = _build_description(prices)
  26. assert 'Discount: $10 / 10%' in result
  27. def test_build_description_service_with_retail():
  28. prices = PriceData(base=100, net=100, service_prices={'airbnb': 115}, service_retail={'airbnb': 130})
  29. result = _build_description(prices)
  30. assert 'Airbnb: $115 / $130' in result
  31. def test_build_description_service_without_retail():
  32. prices = PriceData(base=100, net=100, service_prices={'airbnb': 115})
  33. result = _build_description(prices)
  34. assert 'Airbnb: $115' in result
  35. assert '/' not in result
  36. def test_build_description_multiple_services_sorted():
  37. prices = PriceData(
  38. base=100, net=100,
  39. service_prices={'booking': 120, 'airbnb': 115},
  40. service_retail={'booking': 140, 'airbnb': 130},
  41. )
  42. lines = _build_description(prices).splitlines()
  43. service_lines = [l for l in lines if l.startswith('Airbnb') or l.startswith('Booking')]
  44. assert service_lines[0].startswith('Airbnb')
  45. assert service_lines[1].startswith('Booking')
  46. @pytest.mark.asyncio
  47. async def test_room_price_calendars_set_readback():
  48. cals = CalPrice()
  49. # Find a past date that has a price so we can restore it cleanly.
  50. # Past dates are safe: even if the test leaves stale data it won't affect live bookings.
  51. target = None
  52. original = None
  53. d = date.today() - timedelta(days=90)
  54. end = date.today() - timedelta(days=70)
  55. while d <= end:
  56. full = await cals._get_prices(d)
  57. if full is not None:
  58. target = d
  59. original = full.net
  60. break
  61. d += timedelta(days=1)
  62. if target is None:
  63. pytest.skip("No priced date found in the past 70–90 days")
  64. test_price = original + 2
  65. try:
  66. await cals.set(target, test_price)
  67. prices = await cals._get_prices(target)
  68. assert prices is not None, "No price event found after set"
  69. assert round(prices.net) == round(test_price), \
  70. f"Net mismatch: expected {round(test_price)}, got {prices.net}"
  71. for service in cals._services:
  72. expected = round(net_to_list(service, test_price))
  73. assert round(prices.service_prices[service]) == expected, \
  74. f"{service} mismatch: expected {expected}, got {prices.service_prices[service]}"
  75. finally:
  76. await cals.set(target, original)