"""Tests for physical reporting product detail handler.""" import json from unittest.mock import MagicMock import pytest from reporting.logic import physical_reporting as pr VENDOR_IDS = [1001, 1002] PRODUCT_DETAIL_URL = '/physical-reporting/product-detail' PRODUCT_DETAIL_RESULT = [ { 'label_nm': 'Fat Wreck Chords', 'subacct_nm': 'Fat Wreck Chords', 'artist_nm': 'Good Riddance', 'product_nm': 'Peace in Our Time', 'product_cd': '709422', 'upc_cd': 751097094228, 'display_configuration': '1 x CD Album', 'status_nm': 'Active Catalog', 'release_dt': '2015-04-21', 'exclusive_for': '', 'price_cd': 9, 'series_cd': 13.98, 'units_per_set': 1, 'genre_nm': 'Punk', 'subgenre_nm': 'Punk', 'order_qt': 500, 'back_order_qt': 0, 'yest_ship_qt': 150, 'mtd_ship_qt': 206, 'ytd_ship_qt': 50, 'rtd_ship_qt': 8495, 'yest_return_qt': 0, 'mtd_return_qt': 0, 'ytd_return_qt': -5, 'rtd_return_qt': -1395, 'yest_net_qt': 150, 'mtd_net_qt': 206, 'ytd_net_qt': 45, 'rtd_net_qt': 7100, 'order_am': 4500.0, 'back_order_am': 0.0, 'yest_ship_am': 1200.0, 'mtd_ship_am': 1844.82, 'ytd_ship_am': 396.45, 'rtd_ship_am': 72375.3, 'yest_return_am': 0.0, 'mtd_return_am': 0.0, 'ytd_return_am': -45.0, 'rtd_return_am': -11635.2, 'yest_net_am': 1200.0, 'mtd_net_am': 1844.82, 'ytd_net_am': 351.45, 'rtd_net_am': 60740.1, 'vendor_id': 1001, 'subacct_id': 7483, }, ] def test_physical_reporting_product_detail_success(client, monkeypatch): """Test product detail handler returns 200 with results.""" monkeypatch.setattr( pr, 'get_product_detail', value=MagicMock(return_value={'results': PRODUCT_DETAIL_RESULT}), ) result = client.post(PRODUCT_DETAIL_URL, json={'vendor_ids': VENDOR_IDS}) assert result.status_code == 200 body = json.loads(result.data) assert body == {'results': PRODUCT_DETAIL_RESULT} pr.get_product_detail.assert_called_once_with(VENDOR_IDS, None) def test_physical_reporting_product_detail_with_subacct_ids( client, monkeypatch ): """Test product detail passes subacct_ids to logic when provided.""" monkeypatch.setattr( pr, 'get_product_detail', value=MagicMock(return_value={'results': PRODUCT_DETAIL_RESULT}), ) result = client.post( PRODUCT_DETAIL_URL, json={'vendor_ids': VENDOR_IDS, 'subacct_ids': [7483, 7484]}, ) assert result.status_code == 200 body = json.loads(result.data) assert body == {'results': PRODUCT_DETAIL_RESULT} pr.get_product_detail.assert_called_once_with(VENDOR_IDS, [7483, 7484]) def test_physical_reporting_product_detail_empty_results(client, monkeypatch): """Test product detail handler returns 200 with empty list.""" monkeypatch.setattr( pr, 'get_product_detail', value=MagicMock(return_value={'results': []}), ) result = client.post(PRODUCT_DETAIL_URL, json={'vendor_ids': VENDOR_IDS}) assert result.status_code == 200 body = json.loads(result.data) assert body == {'results': []} pr.get_product_detail.assert_called_once_with(VENDOR_IDS, None) def test_physical_reporting_product_detail_exception(client, monkeypatch): """Test product detail handler returns 500 on exception.""" monkeypatch.setattr( pr, 'get_product_detail', value=MagicMock(side_effect=Exception('DB connection failed')), ) result = client.post(PRODUCT_DETAIL_URL, json={'vendor_ids': VENDOR_IDS}) assert result.status_code == 500 @pytest.mark.parametrize( 'payload', [ pytest.param({'vendor_ids': []}, id='empty vendor_ids'), pytest.param({}, id='missing vendor_ids'), pytest.param({'vendor_ids': None}, id='null vendor_ids'), ], ) def test_physical_reporting_product_detail_invalid_input( client, monkeypatch, payload ): """Test returns 400 for invalid vendor_ids.""" mock_logic = MagicMock() monkeypatch.setattr(pr, 'get_product_detail', value=mock_logic) result = client.post(PRODUCT_DETAIL_URL, json=payload) assert result.status_code == 400 body = json.loads(result.data) assert body['code'] == 'bad_request' assert 'vendor_ids' in body['message'] mock_logic.assert_not_called()