Spaces:
Paused
Paused
feat(customers): add endpoint to retrieve projects associated with a specific customer with pagination
f5b378b | import pytest | |
| from unittest.mock import Mock | |
| from app.services.project_service import ProjectService | |
| from app.schemas.project_detail import ProjectCustomerOut, BarrierSizeOut, ContactOut, BidderNoteOut | |
| from unittest.mock import MagicMock | |
| import app.controllers.projects as projects_controller | |
| import app.controllers.customers as customers_controller | |
| def make_sample_bidder_row(): | |
| return { | |
| 'proj_no': 123, | |
| 'cust_id': 'CUST123', | |
| 'quote': None, | |
| 'contact': 'Jane Doe', | |
| 'phone': '555-1234', | |
| 'notes': 'Important customer', | |
| 'date_last_contact': None, | |
| 'date_followup': None, | |
| 'is_primary': 1, | |
| 'cust_type': 2, | |
| 'email_address': 'jane@example.com', | |
| 'Id': 10, | |
| 'fax': None, | |
| 'order_nr': None, | |
| 'customer_po': None, | |
| 'ship_date': None, | |
| 'deliver_date': None, | |
| 'replacement_cost': None, | |
| 'quote_date': None, | |
| 'invoice_date': None, | |
| 'less_payment': None, | |
| 'enabled': 1, | |
| 'employee_id': 5 | |
| } | |
| def test_get_customers_service_calls_repo_methods(monkeypatch): | |
| mock_db = Mock() | |
| service = ProjectService(mock_db) | |
| # Mock BidderRepository since service now creates its own instance | |
| from app.db.repositories.bidder_repo import BidderRepository | |
| mock_bidder_repo = Mock(spec=BidderRepository) | |
| mock_bidder_repo.fetch_project_bidders_raw = Mock(return_value=[make_sample_bidder_row()]) | |
| mock_bidder_repo.get_bidder_barrier_sizes_raw = Mock(return_value=[{'Id': 1, 'InventoryId': 'INV1', 'BarrierSizeId': 42, 'InstallAdvisorFees': None, 'IsStandard': 1, 'Width': 10, 'Length': 20, 'CableUnits': 2, 'Height': 5, 'Price': None}]) | |
| mock_bidder_repo.get_bidder_contacts_raw = Mock(return_value=[{'Id': 2, 'ContactId': 200, 'BidderId': 10, 'Enabled': 1, 'FirstName': 'John', 'LastName': 'Smith', 'Title': 'Mgr', 'EmailAddress': 'john@example.com', 'WorkPhone': '555', 'MobilePhone': '999'}]) | |
| mock_bidder_repo.get_bidder_notes_raw = Mock(return_value=[{'Id': 3, 'BidderId': 10, 'Date': '2020-01-01T00:00:00', 'EmployeeID': '5', 'Notes': 'Note text'}]) | |
| # Patch BidderRepository instantiation | |
| def fake_bidder_repo_init(db): | |
| return mock_bidder_repo | |
| monkeypatch.setattr('app.db.repositories.bidder_repo.BidderRepository', fake_bidder_repo_init) | |
| customers = service.get_customers(123) | |
| assert isinstance(customers, list) | |
| assert len(customers) == 1 | |
| cust = customers[0] | |
| assert isinstance(cust, ProjectCustomerOut) | |
| assert cust.cust_id == 'CUST123' | |
| assert cust.contact == 'Jane Doe' | |
| assert cust.id == 10 | |
| assert len(cust.barrier_sizes) == 1 | |
| assert len(cust.contacts) == 1 | |
| assert len(cust.bidder_notes) == 1 | |
| def test_get_project_customers_endpoint_monkeypatched(monkeypatch): | |
| # Monkeypatch the ProjectService.get_customers to return a known value | |
| sample = ProjectCustomerOut( | |
| proj_no=123, | |
| cust_id='CUST999', | |
| quote=None, | |
| contact='Endpoint User', | |
| phone='123', | |
| notes=None, | |
| date_last_contact=None, | |
| date_followup=None, | |
| primary=True, | |
| cust_type='1', | |
| email_address='end@example.com', | |
| id=99, | |
| fax=None, | |
| order_nr=None, | |
| customer_po=None, | |
| ship_date=None, | |
| deliver_date=None, | |
| replacement_cost=None, | |
| quote_date=None, | |
| invoice_date=None, | |
| less_payment=None, | |
| barrier_sizes=[], | |
| contacts=[], | |
| bidder_notes=[], | |
| bid_date=None, | |
| enabled=True, | |
| employee_id=None | |
| ) | |
| def fake_get_customers(self, project_no, page=1, page_size=100): | |
| return [sample] | |
| monkeypatch.setattr('app.services.project_service.ProjectService.get_customers', fake_get_customers) | |
| # Call controller function directly, injecting a mock DB session | |
| fake_db = MagicMock() | |
| result = projects_controller.get_project_customers(123, page=1, page_size=10, db=fake_db) | |
| assert isinstance(result, list) | |
| assert result[0].cust_id == 'CUST999' | |
| assert result[0].id == 99 | |
| def test_get_project_customer_detail_service(monkeypatch): | |
| """Test ProjectService.get_project_customer_detail method""" | |
| mock_db = Mock() | |
| service = ProjectService(mock_db) | |
| sample_bidder = make_sample_bidder_row() | |
| sample_bidder['cust_id'] = 'CUST456' | |
| # Mock BidderRepository methods | |
| from app.db.repositories.bidder_repo import BidderRepository | |
| mock_bidder_repo = Mock(spec=BidderRepository) | |
| mock_bidder_repo.fetch_project_bidder_by_customer_id_raw = Mock(return_value=sample_bidder) | |
| mock_bidder_repo.get_bidder_barrier_sizes_raw = Mock(return_value=[]) | |
| mock_bidder_repo.get_bidder_contacts_raw = Mock(return_value=[]) | |
| mock_bidder_repo.get_bidder_notes_raw = Mock(return_value=[]) | |
| # Patch BidderRepository instantiation | |
| def fake_bidder_repo_init(db): | |
| return mock_bidder_repo | |
| monkeypatch.setattr('app.db.repositories.bidder_repo.BidderRepository', fake_bidder_repo_init) | |
| customer = service.get_project_customer_detail(123, 'CUST456') | |
| assert isinstance(customer, ProjectCustomerOut) | |
| assert customer.cust_id == 'CUST456' | |
| assert customer.id == 10 | |
| assert customer.contact == 'Jane Doe' | |
| mock_bidder_repo.fetch_project_bidder_by_customer_id_raw.assert_called_once_with(123, 'CUST456') | |
| def test_get_project_customer_detail_endpoint(monkeypatch): | |
| """Test controller endpoint for specific customer detail""" | |
| sample = ProjectCustomerOut( | |
| proj_no=123, | |
| cust_id='CUST777', | |
| quote=None, | |
| contact='Detail User', | |
| phone='456', | |
| notes='Specific customer', | |
| date_last_contact=None, | |
| date_followup=None, | |
| primary=False, | |
| cust_type='2', | |
| email_address='detail@example.com', | |
| id=77, | |
| fax=None, | |
| order_nr='ORD123', | |
| customer_po='PO456', | |
| ship_date=None, | |
| deliver_date=None, | |
| replacement_cost=None, | |
| quote_date=None, | |
| invoice_date=None, | |
| less_payment=None, | |
| barrier_sizes=[], | |
| contacts=[], | |
| bidder_notes=[], | |
| bid_date=None, | |
| enabled=True, | |
| employee_id='EMP5' | |
| ) | |
| def fake_get_customer_detail(self, project_no, customer_id): | |
| return sample | |
| monkeypatch.setattr('app.services.project_service.ProjectService.get_project_customer_detail', fake_get_customer_detail) | |
| fake_db = MagicMock() | |
| result = projects_controller.get_project_customer_detail(123, 'CUST777', db=fake_db) | |
| assert isinstance(result, ProjectCustomerOut) | |
| assert result.cust_id == 'CUST777' | |
| assert result.id == 77 | |
| assert result.order_nr == 'ORD123' | |
| assert result.employee_id == 'EMP5' | |
| def test_get_customer_projects_service(monkeypatch): | |
| """Test ProjectService.get_customer_projects method""" | |
| mock_db = Mock() | |
| service = ProjectService(mock_db) | |
| # Create sample bidders for multiple projects | |
| bidder1 = make_sample_bidder_row() | |
| bidder1['proj_no'] = 100 | |
| bidder1['cust_id'] = 'CUST888' | |
| bidder1['Id'] = 20 | |
| bidder2 = make_sample_bidder_row() | |
| bidder2['proj_no'] = 200 | |
| bidder2['cust_id'] = 'CUST888' | |
| bidder2['Id'] = 21 | |
| # Mock BidderRepository methods | |
| from app.db.repositories.bidder_repo import BidderRepository | |
| mock_bidder_repo = Mock(spec=BidderRepository) | |
| mock_bidder_repo.fetch_bidders_by_customer_id_raw = Mock(return_value=[bidder1, bidder2]) | |
| mock_bidder_repo.get_bidder_barrier_sizes_raw = Mock(return_value=[]) | |
| mock_bidder_repo.get_bidder_contacts_raw = Mock(return_value=[]) | |
| mock_bidder_repo.get_bidder_notes_raw = Mock(return_value=[]) | |
| # Patch BidderRepository instantiation | |
| def fake_bidder_repo_init(db): | |
| return mock_bidder_repo | |
| monkeypatch.setattr('app.db.repositories.bidder_repo.BidderRepository', fake_bidder_repo_init) | |
| projects = service.get_customer_projects('CUST888', page=1, page_size=10) | |
| assert isinstance(projects, list) | |
| assert len(projects) == 2 | |
| assert projects[0].proj_no == 100 | |
| assert projects[0].cust_id == 'CUST888' | |
| assert projects[1].proj_no == 200 | |
| assert projects[1].cust_id == 'CUST888' | |
| mock_bidder_repo.fetch_bidders_by_customer_id_raw.assert_called_once_with('CUST888', page=1, page_size=10) | |
| def test_get_customer_projects_endpoint(monkeypatch): | |
| """Test controller endpoint for customer projects""" | |
| sample1 = ProjectCustomerOut( | |
| proj_no=300, | |
| cust_id='CUST555', | |
| quote=None, | |
| contact='Project A Contact', | |
| phone='111', | |
| notes=None, | |
| date_last_contact=None, | |
| date_followup=None, | |
| primary=True, | |
| cust_type='1', | |
| email_address='a@example.com', | |
| id=30, | |
| fax=None, | |
| order_nr=None, | |
| customer_po=None, | |
| ship_date=None, | |
| deliver_date=None, | |
| replacement_cost=None, | |
| quote_date=None, | |
| invoice_date=None, | |
| less_payment=None, | |
| barrier_sizes=[], | |
| contacts=[], | |
| bidder_notes=[], | |
| bid_date=None, | |
| enabled=True, | |
| employee_id=None | |
| ) | |
| sample2 = ProjectCustomerOut( | |
| proj_no=400, | |
| cust_id='CUST555', | |
| quote=None, | |
| contact='Project B Contact', | |
| phone='222', | |
| notes=None, | |
| date_last_contact=None, | |
| date_followup=None, | |
| primary=False, | |
| cust_type='2', | |
| email_address='b@example.com', | |
| id=31, | |
| fax=None, | |
| order_nr=None, | |
| customer_po=None, | |
| ship_date=None, | |
| deliver_date=None, | |
| replacement_cost=None, | |
| quote_date=None, | |
| invoice_date=None, | |
| less_payment=None, | |
| barrier_sizes=[], | |
| contacts=[], | |
| bidder_notes=[], | |
| bid_date=None, | |
| enabled=True, | |
| employee_id=None | |
| ) | |
| def fake_get_customer_projects(self, customer_id, page=1, page_size=100): | |
| return [sample1, sample2] | |
| monkeypatch.setattr('app.services.project_service.ProjectService.get_customer_projects', fake_get_customer_projects) | |
| fake_db = MagicMock() | |
| result = customers_controller.get_customer_projects('CUST555', page=1, page_size=10, db=fake_db) | |
| assert isinstance(result, list) | |
| assert len(result) == 2 | |
| assert result[0].proj_no == 300 | |
| assert result[0].cust_id == 'CUST555' | |
| assert result[1].proj_no == 400 | |
| assert result[1].cust_id == 'CUST555' |