Skip to content

Commit 2f6d42a

Browse files
authored
Merge pull request #89 from govtechmy/fix/phone-number-format
fix(gsheet): fetch gsheet as xlsx, not csv
2 parents 2c276de + 3ae2951 commit 2f6d42a

3 files changed

Lines changed: 43 additions & 8 deletions

File tree

src/core/gsheet.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,17 @@ def fetch_csv_data(gsheet_id: str, gid: str) -> tuple[bytes, str | None]:
5656
content_disp = response.headers.get("Content-Disposition", "")
5757
filename = _extract_filename(content_disp)
5858

59+
return response.content, filename
60+
61+
def fetch_xlsx_data(gsheet_id: str, gid: str) -> tuple[bytes, str | None]:
62+
"""Fetch Google Sheet as XLSX to preserve actual cell values (not display format)."""
63+
url = f"https://docs.google.com/spreadsheets/d/{gsheet_id}/export?format=xlsx&gid={gid}"
64+
logger.info("Fetching XLSX data from URL: %s", url)
65+
66+
response = requests.get(url)
67+
response.raise_for_status()
68+
69+
content_disp = response.headers.get("Content-Disposition", "")
70+
filename = _extract_filename(content_disp)
71+
5972
return response.content, filename

src/core/s3.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,23 @@ def _upload_to_s3(csv_bytes: bytes, bucket: str, prefix: str, source_filename: s
2828

2929
return s3_key
3030

31+
def _upload_xlsx_to_s3(xlsx_bytes: bytes, bucket: str, prefix: str, source_filename: str | None = None,) -> str:
32+
if not bucket:
33+
bucket = get_s3_bucket_name()
34+
35+
timestamp = int(time.time())
36+
version = _extract_file_version(source_filename) or "unknown"
37+
s3_key = f"{prefix}/{version}/{timestamp}.xlsx"
38+
39+
s3.put_object(
40+
Bucket=bucket,
41+
Key=s3_key,
42+
Body=xlsx_bytes,
43+
ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
44+
)
45+
46+
return s3_key
47+
3148
def _list_csv_files_in_s3(bucket: str, prefix: str) -> list[str]:
3249
response = s3.list_objects_v2(Bucket=bucket, Prefix=prefix)
3350

@@ -46,6 +63,11 @@ def _read_csv_from_s3(bucket: str, s3_key: str) -> pd.DataFrame:
4663
response = s3.get_object(Bucket=bucket, Key=s3_key)
4764
return pd.read_csv(response["Body"], dtype=str).fillna("")
4865

66+
def _read_xlsx_from_s3(bucket: str, s3_key: str) -> pd.DataFrame:
67+
import io
68+
response = s3.get_object(Bucket=bucket, Key=s3_key)
69+
return pd.read_excel(io.BytesIO(response["Body"].read()), dtype=str).fillna("")
70+
4971
def upload_json_to_s3(payload: dict | list, bucket: Optional[str], key: str) -> str:
5072
"""
5173
Upload JSON to a fixed S3 key (no timestamp).

src/pipeline/ingestion.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717

1818
from src.config import Settings, get_settings
1919
from src.models import Sekolah
20-
from src.core.gsheet import fetch_csv_data, _extract_file_version
21-
from src.core.s3 import (_upload_to_s3, _latest_csv_from_s3, _read_csv_from_s3)
20+
from src.core.gsheet import fetch_xlsx_data, _extract_file_version
21+
from src.core.s3 import (_upload_xlsx_to_s3, _read_xlsx_from_s3)
2222
from src.models.sekolah import SekolahStatus
2323
from src.pipeline.status_sync import sync_entiti_statuses, delete_inactive_entiti
2424
from src.core.time import _utc_now
@@ -99,13 +99,13 @@ def _read_google_sheet(sheet_id: str, gid: str) -> Iterable[Dict[str, Any]]:
9999

100100

101101
def _load_rows(settings: Settings) -> tuple[Iterable[Dict[str, Any]], str | None]:
102-
csv_bytes, file_name = fetch_csv_data(settings.gsheet_id, settings.gsheet_gid)
103-
logger.info("Uploading CSV data to S3 bucket %s", settings.s3_bucket_dataproc)
104-
s3_key = _upload_to_s3(csv_bytes, settings.s3_bucket_dataproc, settings.s3_prefix_sekolah, file_name)
105-
logger.info("CSV uploaded to S3 at key: %s", s3_key)
102+
xlsx_bytes, file_name = fetch_xlsx_data(settings.gsheet_id, settings.gsheet_gid)
103+
logger.info("Uploading XLSX data to S3 bucket %s", settings.s3_bucket_dataproc)
104+
s3_key = _upload_xlsx_to_s3(xlsx_bytes, settings.s3_bucket_dataproc, settings.s3_prefix_sekolah, file_name)
105+
logger.info("XLSX uploaded to S3 at key: %s", s3_key)
106106

107-
df = _read_csv_from_s3(settings.s3_bucket_dataproc, s3_key)
108-
logger.info("CSV loaded from S3: %d rows, %d columns", df.shape[0], df.shape[1])
107+
df = _read_xlsx_from_s3(settings.s3_bucket_dataproc, s3_key)
108+
logger.info("XLSX loaded from S3: %d rows, %d columns", df.shape[0], df.shape[1])
109109
return df.to_dict(orient="records"), file_name
110110

111111

0 commit comments

Comments
 (0)