|
| 1 | +from datetime import date |
1 | 2 | from unittest import mock |
2 | 3 | import pytest |
3 | | -from allocation import services, exceptions, repository, unit_of_work |
| 4 | +from allocation import events, services, exceptions, repository, unit_of_work |
4 | 5 |
|
5 | 6 |
|
6 | 7 | class FakeRepository(repository.AbstractRepository): |
@@ -30,49 +31,87 @@ def rollback(self): |
30 | 31 |
|
31 | 32 |
|
32 | 33 |
|
33 | | -def test_add_batch_for_new_product(): |
34 | | - uow = FakeUnitOfWork() |
35 | | - services.add_batch("b1", "CRUNCHY-ARMCHAIR", 100, None, uow) |
36 | | - assert uow.products.get("CRUNCHY-ARMCHAIR") is not None |
37 | | - assert uow.committed |
| 34 | +class TestAddBatch: |
38 | 35 |
|
| 36 | + @staticmethod |
| 37 | + def test_for_new_product(): |
| 38 | + uow = FakeUnitOfWork() |
| 39 | + services.add_batch("b1", "CRUNCHY-ARMCHAIR", 100, None, uow) |
| 40 | + assert uow.products.get("CRUNCHY-ARMCHAIR") is not None |
| 41 | + assert uow.committed |
39 | 42 |
|
40 | | -def test_add_batch_for_existing_product(): |
41 | | - uow = FakeUnitOfWork() |
42 | | - services.add_batch("b1", "GARISH-RUG", 100, None, uow) |
43 | | - services.add_batch("b2", "GARISH-RUG", 99, None, uow) |
44 | | - assert "b2" in [b.reference for b in uow.products.get("GARISH-RUG").batches] |
| 43 | + @staticmethod |
| 44 | + def test_for_existing_product(): |
| 45 | + uow = FakeUnitOfWork() |
| 46 | + services.add_batch("b1", "GARISH-RUG", 100, None, uow) |
| 47 | + services.add_batch("b2", "GARISH-RUG", 99, None, uow) |
| 48 | + assert "b2" in [b.reference for b in uow.products.get("GARISH-RUG").batches] |
45 | 49 |
|
46 | 50 |
|
47 | | -def test_allocate_returns_allocation(): |
48 | | - uow = FakeUnitOfWork() |
49 | | - services.add_batch("batch1", "COMPLICATED-LAMP", 100, None, uow) |
50 | | - result = services.allocate("o1", "COMPLICATED-LAMP", 10, uow) |
51 | | - assert result == "batch1" |
| 51 | +class TestAllocate: |
52 | 52 |
|
| 53 | + @staticmethod |
| 54 | + def test_returns_allocation(): |
| 55 | + uow = FakeUnitOfWork() |
| 56 | + services.add_batch("batch1", "COMPLICATED-LAMP", 100, None, uow) |
| 57 | + result = services.allocate("o1", "COMPLICATED-LAMP", 10, uow) |
| 58 | + assert result == "batch1" |
53 | 59 |
|
54 | | -def test_allocate_errors_for_invalid_sku(): |
55 | | - uow = FakeUnitOfWork() |
56 | | - services.add_batch("b1", "AREALSKU", 100, None, uow) |
| 60 | + @staticmethod |
| 61 | + def test_errors_for_invalid_sku(): |
| 62 | + uow = FakeUnitOfWork() |
| 63 | + services.add_batch("b1", "AREALSKU", 100, None, uow) |
57 | 64 |
|
58 | | - with pytest.raises(exceptions.InvalidSku, match="Invalid sku NONEXISTENTSKU"): |
59 | | - services.allocate("o1", "NONEXISTENTSKU", 10, uow) |
| 65 | + with pytest.raises(exceptions.InvalidSku, match="Invalid sku NONEXISTENTSKU"): |
| 66 | + services.allocate("o1", "NONEXISTENTSKU", 10, uow) |
60 | 67 |
|
| 68 | + @staticmethod |
| 69 | + def test_commits(): |
| 70 | + uow = FakeUnitOfWork() |
| 71 | + services.add_batch("b1", "OMINOUS-MIRROR", 100, None, uow) |
| 72 | + services.allocate("o1", "OMINOUS-MIRROR", 10, uow) |
| 73 | + assert uow.committed |
61 | 74 |
|
62 | | -def test_allocate_commits(): |
63 | | - uow = FakeUnitOfWork() |
64 | | - services.add_batch("b1", "OMINOUS-MIRROR", 100, None, uow) |
65 | | - services.allocate("o1", "OMINOUS-MIRROR", 10, uow) |
66 | | - assert uow.committed |
| 75 | + @staticmethod |
| 76 | + def test_sends_email_on_out_of_stock_error(): |
| 77 | + uow = FakeUnitOfWork() |
| 78 | + services.add_batch("b1", "POPULAR-CURTAINS", 9, None, uow) |
67 | 79 |
|
| 80 | + with mock.patch("allocation.email.send_mail") as mock_send_mail: |
| 81 | + services.allocate("o1", "POPULAR-CURTAINS", 10, uow) |
| 82 | + assert mock_send_mail.call_args == mock.call( |
| 83 | + |
| 84 | + f"Out of stock for POPULAR-CURTAINS", |
| 85 | + ) |
68 | 86 |
|
69 | | -def test_sends_email_on_out_of_stock_error(): |
70 | | - uow = FakeUnitOfWork() |
71 | | - services.add_batch("b1", "POPULAR-CURTAINS", 9, None, uow) |
72 | 87 |
|
73 | | - with mock.patch("allocation.email.send_mail") as mock_send_mail: |
74 | | - services.allocate("o1", "POPULAR-CURTAINS", 10, uow) |
75 | | - assert mock_send_mail.call_args == mock.call( |
76 | | - |
77 | | - f"Out of stock for POPULAR-CURTAINS", |
78 | | - ) |
| 88 | +class TestChangeBatchQuantity: |
| 89 | + |
| 90 | + @staticmethod |
| 91 | + def test_changes_available_quantity(): |
| 92 | + uow = FakeUnitOfWork() |
| 93 | + services.add_batch("batch1", "ADORABLE-SETTEE", 100, None, uow) |
| 94 | + [batch] = uow.products.get(sku="ADORABLE-SETTEE").batches |
| 95 | + assert batch.available_quantity == 100 |
| 96 | + |
| 97 | + services.change_batch_quantity("batch1", 50, uow) |
| 98 | + |
| 99 | + assert batch.available_quantity == 50 |
| 100 | + |
| 101 | + |
| 102 | + @staticmethod |
| 103 | + def test_reallocates_if_necessary(): |
| 104 | + uow = FakeUnitOfWork() |
| 105 | + services.add_batch("batch1", "INDIFFERENT-TABLE", 50, None, uow) |
| 106 | + services.add_batch("batch2", "INDIFFERENT-TABLE", 50, date.today(), uow) |
| 107 | + services.allocate("order1", "INDIFFERENT-TABLE", 20, uow) |
| 108 | + services.allocate("order2", "INDIFFERENT-TABLE", 20, uow) |
| 109 | + [batch1, batch2] = uow.products.get(sku="sku1").batches |
| 110 | + assert batch1.available_quantity == 10 |
| 111 | + |
| 112 | + services.change_batch_quantity("batch1", 25, uow) |
| 113 | + |
| 114 | + # order1 or order2 will be deallocated, so we"ll have 25 - 20 * 1 |
| 115 | + assert batch1.available_quantity == 5 |
| 116 | + # and 20 will be reallocated to the next batch |
| 117 | + assert batch2.available_quantity == 30 |
0 commit comments