Fix Costco receipt enumeration windows
This commit is contained in:
@@ -3,6 +3,7 @@ import json
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
import enrich_costco
|
||||
import scrape_costco
|
||||
@@ -10,6 +11,82 @@ import validate_cross_retailer_flow
|
||||
|
||||
|
||||
class CostcoPipelineTests(unittest.TestCase):
|
||||
def test_build_date_windows_splits_long_ranges(self):
|
||||
windows = scrape_costco.build_date_windows("1/01/2026", "6/30/2026", 92)
|
||||
|
||||
self.assertEqual(
|
||||
[
|
||||
{"startDate": "1/01/2026", "endDate": "4/02/2026"},
|
||||
{"startDate": "4/03/2026", "endDate": "6/30/2026"},
|
||||
],
|
||||
windows,
|
||||
)
|
||||
|
||||
def test_fetch_summary_windows_records_metadata_and_warns_on_mismatch(self):
|
||||
payloads = [
|
||||
{
|
||||
"data": {
|
||||
"receiptsWithCounts": {
|
||||
"inWarehouse": 2,
|
||||
"gasStation": 0,
|
||||
"carWash": 0,
|
||||
"gasAndCarWash": 0,
|
||||
"receipts": [
|
||||
{
|
||||
"transactionBarcode": "abc",
|
||||
"receiptType": "In-Warehouse",
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"receiptsWithCounts": {
|
||||
"inWarehouse": 1,
|
||||
"gasStation": 0,
|
||||
"carWash": 0,
|
||||
"gasAndCarWash": 0,
|
||||
"receipts": [
|
||||
{
|
||||
"transactionBarcode": "def",
|
||||
"receiptType": "In-Warehouse",
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
with mock.patch.object(
|
||||
scrape_costco, "graphql_post", side_effect=payloads
|
||||
) as mocked_post, mock.patch.object(scrape_costco.click, "echo") as mocked_echo:
|
||||
summary_payload, metadata = scrape_costco.fetch_summary_windows(
|
||||
session=object(),
|
||||
start_date="1/01/2026",
|
||||
end_date="6/30/2026",
|
||||
document_type="all",
|
||||
document_sub_type="all",
|
||||
window_days=92,
|
||||
)
|
||||
|
||||
self.assertEqual(2, mocked_post.call_count)
|
||||
self.assertEqual(2, len(metadata))
|
||||
self.assertTrue(metadata[0]["countMismatch"])
|
||||
self.assertFalse(metadata[1]["countMismatch"])
|
||||
self.assertEqual("1/01/2026", metadata[0]["startDate"])
|
||||
self.assertEqual("4/03/2026", metadata[1]["startDate"])
|
||||
self.assertEqual(
|
||||
["abc", "def"],
|
||||
[
|
||||
row["transactionBarcode"]
|
||||
for row in scrape_costco.summary_receipts(summary_payload)
|
||||
],
|
||||
)
|
||||
mocked_echo.assert_called_once()
|
||||
warning_text = mocked_echo.call_args.args[0]
|
||||
self.assertIn("warning: summary count mismatch", warning_text)
|
||||
|
||||
def test_flatten_costco_data_preserves_discount_rows(self):
|
||||
summary_payload = {
|
||||
"data": {
|
||||
@@ -196,6 +273,99 @@ class CostcoPipelineTests(unittest.TestCase):
|
||||
self.assertEqual(1, len(rows))
|
||||
self.assertEqual("banana", rows[0]["proof_name"])
|
||||
|
||||
def test_main_writes_summary_request_metadata(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
outdir = Path(tmpdir) / "costco_output"
|
||||
summary_payload = {
|
||||
"data": {
|
||||
"receiptsWithCounts": {
|
||||
"inWarehouse": 1,
|
||||
"gasStation": 0,
|
||||
"carWash": 0,
|
||||
"gasAndCarWash": 0,
|
||||
"receipts": [
|
||||
{
|
||||
"transactionBarcode": "abc",
|
||||
"receiptType": "In-Warehouse",
|
||||
"tenderArray": [],
|
||||
"couponArray": [],
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
detail_payload = {
|
||||
"data": {
|
||||
"receiptsWithCounts": {
|
||||
"receipts": [
|
||||
{
|
||||
"transactionBarcode": "abc",
|
||||
"transactionDate": "2026-03-12",
|
||||
"receiptType": "In-Warehouse",
|
||||
"total": 10.0,
|
||||
"totalItemCount": 1,
|
||||
"instantSavings": 0,
|
||||
"warehouseName": "MT VERNON",
|
||||
"warehouseNumber": 1115,
|
||||
"warehouseAddress1": "7940 RICHMOND HWY",
|
||||
"warehouseCity": "ALEXANDRIA",
|
||||
"warehouseState": "VA",
|
||||
"warehousePostalCode": "22306",
|
||||
"itemArray": [],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
metadata = [
|
||||
{
|
||||
"startDate": "1/01/2026",
|
||||
"endDate": "3/31/2026",
|
||||
"text": "custom",
|
||||
"documentType": "all",
|
||||
"documentSubType": "all",
|
||||
"returnedReceipts": 1,
|
||||
"returnedInWarehouseReceipts": 1,
|
||||
"inWarehouse": 1,
|
||||
"gasStation": 0,
|
||||
"carWash": 0,
|
||||
"gasAndCarWash": 0,
|
||||
"countMismatch": False,
|
||||
}
|
||||
]
|
||||
|
||||
with mock.patch.object(
|
||||
scrape_costco, "load_config",
|
||||
return_value={
|
||||
"authorization": "token",
|
||||
"client_id": "client",
|
||||
"client_identifier": "identifier",
|
||||
},
|
||||
), mock.patch.object(
|
||||
scrape_costco, "build_session", return_value=object()
|
||||
), mock.patch.object(
|
||||
scrape_costco,
|
||||
"fetch_summary_windows",
|
||||
return_value=(summary_payload, metadata),
|
||||
), mock.patch.object(
|
||||
scrape_costco,
|
||||
"graphql_post",
|
||||
return_value=detail_payload,
|
||||
):
|
||||
scrape_costco.main.callback(
|
||||
start_date="1/01/2026",
|
||||
end_date="3/31/2026",
|
||||
outdir=str(outdir),
|
||||
document_type="all",
|
||||
document_sub_type="all",
|
||||
window_days=92,
|
||||
)
|
||||
|
||||
metadata_path = outdir / "raw" / "summary_requests.json"
|
||||
self.assertTrue(metadata_path.exists())
|
||||
saved_metadata = json.loads(metadata_path.read_text(encoding="utf-8"))
|
||||
self.assertEqual(metadata, saved_metadata)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user