File size: 11,491 Bytes
1c0bd9a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
"""
ExportGuard β€” BigQuery One-Click Setup.

Run this AFTER setting up a Google Cloud project and service account.

Usage:
    set GOOGLE_APPLICATION_CREDENTIALS=C:\path\to\key.json
    set GOOGLE_CLOUD_PROJECT=your-project-id
    python backend/setup_bigquery.py --dataset=exportguard

This script:
  1. Creates the BigQuery dataset (if not exists)
  2. Creates raw tables (shipments, country_risk, buyer_history)
  3. Loads CSV data from data/raw/ into the tables
  4. Creates the 3 analytics views (buyer_risk_summary, country_risk_trend, shipment_outcomes_by_hs_code)
"""

import argparse
import os
import sys
from pathlib import Path

PROJECT_ROOT = Path(__file__).resolve().parent.parent
DATA_RAW = PROJECT_ROOT / "data" / "raw"
sys.path.insert(0, str(PROJECT_ROOT))

# ── Check credentials ───────────────────────────────────────────────────

def check_credentials():
    cred_path = os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", "")
    project = os.environ.get("GOOGLE_CLOUD_PROJECT", "")
    if not cred_path or not Path(cred_path).exists():
        print("=" * 60)
        print("ERROR: GOOGLE_APPLICATION_CREDENTIALS not set or file not found.")
        print("")
        print("Steps to fix:")
        print("  1. Go to https://console.cloud.google.com/")
        print("  2. Create a new project (or select existing)")
        print("  3. Go to APIs & Services > Library")
        print("  4. Enable 'BigQuery API' and 'Cloud Storage API'")
        print("  5. Go to IAM & Admin > Service Accounts")
        print("  6. Create a new service account β†’ click 'Create and Continue'")
        print("  7. Assign roles:")
        print("       - BigQuery Data Editor")
        print("       - BigQuery Job User")
        print("       - Storage Object Admin")
        print("  8. Click 'Done', then click on the new service account")
        print("  9. Go to 'Keys' tab β†’ 'Add Key' β†’ 'Create New Key' β†’ JSON")
        print(" 10. Download the JSON file to your computer")
        print("")
        print("Then run:")
        print(f'    set GOOGLE_APPLICATION_CREDENTIALS=C:\\path\\to\\downloaded-key.json')
        print(f'    set GOOGLE_CLOUD_PROJECT=your-project-id')
        print(f"    python backend/setup_bigquery.py --dataset=exportguard")
        print("=" * 60)
        return False
    if not project:
        print("ERROR: GOOGLE_CLOUD_PROJECT environment variable not set.")
        print(f'Example: set GOOGLE_CLOUD_PROJECT=my-project-12345')
        return False
    return True


# ── Main setup ──────────────────────────────────────────────────────────

def setup_bigquery(dataset_id: str):
    from google.cloud import bigquery

    client = bigquery.Client()
    project = client.project
    print(f"Using project: {project}")
    print(f"Dataset: {dataset_id}")

    # 1. Create dataset
    dataset_ref = bigquery.DatasetReference(project, dataset_id)
    try:
        client.get_dataset(dataset_ref)
        print(f"[OK] Dataset {dataset_id} already exists")
    except Exception:
        dataset = bigquery.Dataset(dataset_ref)
        dataset.location = "US"
        client.create_dataset(dataset)
        print(f"[OK] Created dataset {dataset_id}")

    # 2. Table schemas
    tables = {
        "shipments": [
            bigquery.SchemaField("shipment_id", "STRING"),
            bigquery.SchemaField("exporter_id", "STRING"),
            bigquery.SchemaField("buyer_id", "STRING"),
            bigquery.SchemaField("buyer_country", "STRING"),
            bigquery.SchemaField("hs_code", "INT64"),
            bigquery.SchemaField("product_category", "STRING"),
            bigquery.SchemaField("shipment_date", "DATE"),
            bigquery.SchemaField("invoice_value_usd", "FLOAT64"),
            bigquery.SchemaField("payment_terms", "STRING"),
            bigquery.SchemaField("payment_delay_days", "INT64"),
            bigquery.SchemaField("was_disputed", "BOOL"),
            bigquery.SchemaField("was_paid_in_full", "BOOL"),
        ],
        "country_risk": [
            bigquery.SchemaField("country", "STRING"),
            bigquery.SchemaField("month", "DATE"),
            bigquery.SchemaField("political_stability_score", "FLOAT64"),
            bigquery.SchemaField("currency_volatility_index", "FLOAT64"),
            bigquery.SchemaField("trade_sanctions_flag", "INT64"),
        ],
        "buyer_history": [
            bigquery.SchemaField("buyer_id", "STRING"),
            bigquery.SchemaField("total_orders", "INT64"),
            bigquery.SchemaField("total_value_usd", "FLOAT64"),
            bigquery.SchemaField("avg_payment_delay_days", "FLOAT64"),
            bigquery.SchemaField("dispute_rate", "FLOAT64"),
            bigquery.SchemaField("paid_in_full_rate", "FLOAT64"),
            bigquery.SchemaField("avg_invoice_value", "FLOAT64"),
            bigquery.SchemaField("first_order_date", "DATE"),
            bigquery.SchemaField("last_order_date", "DATE"),
            bigquery.SchemaField("primary_country", "STRING"),
            bigquery.SchemaField("primary_category", "STRING"),
            bigquery.SchemaField("value_trend", "STRING"),
        ],
    }

    # 3. Create tables + load CSV data
    for table_name, schema in tables.items():
        csv_path = DATA_RAW / f"{table_name}.csv"
        if not csv_path.exists():
            print(f"[SKIP] {csv_path} not found β€” skipping {table_name}")
            continue

        table_id = f"{project}.{dataset_id}.{table_name}"

        # Delete existing table if present
        try:
            client.delete_table(table_id)
        except Exception:
            pass

        table = bigquery.Table(table_id, schema=schema)
        client.create_table(table)
        print(f"[OK] Created table {table_id}")

        # Load CSV
        job_config = bigquery.LoadJobConfig(
            source_format=bigquery.SourceFormat.CSV,
            skip_leading_rows=1,
            schema=schema,
            write_disposition=bigquery.WriteDisposition.WRITE_TRUNCATE,
            autodetect=False,
        )
        with open(csv_path, "rb") as f:
            load_job = client.load_table_from_file(f, table_id, job_config=job_config)
        load_job.result()
        table = client.get_table(table_id)
        print(f"[OK] Loaded {table.num_rows:,} rows into {table_name}")

    # 4. Create views
    views_sql = {
        "buyer_risk_summary": f"""
            CREATE OR REPLACE VIEW `{project}.{dataset_id}.buyer_risk_summary` AS
            WITH buyer_stats AS (
              SELECT
                buyer_id,
                buyer_country,
                COUNT(*) AS total_shipments,
                SUM(invoice_value_usd) AS total_value,
                AVG(payment_delay_days) AS avg_delay_days,
                SAFE_DIVIDE(SUM(CAST(was_disputed AS INT64)), COUNT(*)) AS dispute_rate,
                SAFE_DIVIDE(SUM(CAST(was_paid_in_full AS INT64)), COUNT(*)) AS paid_in_full_rate,
                MAX(shipment_date) AS last_shipment,
                DATE_DIFF(CURRENT_DATE(), MAX(shipment_date), DAY) AS days_since_last_order,
                ROUND(
                  (AVG(payment_delay_days) / 180) * 30
                  + SAFE_DIVIDE(SUM(CAST(was_disputed AS INT64)), COUNT(*)) * 40
                  + (1 - SAFE_DIVIDE(SUM(CAST(was_paid_in_full AS INT64)), COUNT(*))) * 30
                , 1) AS risk_score
              FROM `{project}.{dataset_id}.shipments`
              GROUP BY buyer_id, buyer_country
            )
            SELECT *, CASE
                WHEN risk_score < 30 THEN 'Low Risk'
                WHEN risk_score < 60 THEN 'Medium Risk'
                ELSE 'High Risk'
              END AS risk_category
            FROM buyer_stats
        """,
        "country_risk_trend": f"""
            CREATE OR REPLACE VIEW `{project}.{dataset_id}.country_risk_trend` AS
            SELECT
              country, month,
              political_stability_score,
              currency_volatility_index,
              trade_sanctions_flag,
              ROUND(
                (1 - political_stability_score) * 50
                + currency_volatility_index * 40
                + trade_sanctions_flag * 10
              , 1) AS composite_risk_index
            FROM `{project}.{dataset_id}.country_risk`
            ORDER BY country, month
        """,
        "shipment_outcomes_by_hs_code": f"""
            CREATE OR REPLACE VIEW `{project}.{dataset_id}.shipment_outcomes_by_hs_code` AS
            SELECT
              hs_code, product_category,
              COUNT(*) AS total_shipments,
              SUM(invoice_value_usd) AS total_value_usd,
              ROUND(AVG(invoice_value_usd), 0) AS avg_invoice_value,
              ROUND(AVG(payment_delay_days), 1) AS avg_delay_days,
              SAFE_DIVIDE(SUM(CAST(was_disputed AS INT64)), COUNT(*)) AS dispute_rate,
              SAFE_DIVIDE(SUM(CAST(was_paid_in_full AS INT64)), COUNT(*)) AS paid_in_full_rate,
              COUNTIF(payment_terms = 'advance') AS advance_count,
              COUNTIF(payment_terms = 'lc') AS lc_count,
              COUNTIF(payment_terms LIKE 'credit_%') AS credit_count
            FROM `{project}.{dataset_id}.shipments`
            GROUP BY hs_code, product_category
            ORDER BY total_value_usd DESC
        """,
    }

    for view_name, sql in views_sql.items():
        try:
            job = client.query(sql)
            job.result()
            print(f"[OK] Created view {view_name}")
        except Exception as e:
            print(f"[ERROR] Creating view {view_name}: {e}")

    print(f"\n{'=' * 60}")
    print(f"SETUP COMPLETE!")
    print(f"{'=' * 60}")
    print(f"")
    print(f"BigQuery tables and views are ready at: {project}.{dataset_id}")
    print(f"")
    print(f"Views created:")
    for v in views_sql:
        print(f"  - {v}")
    print(f"")
    print(f"Next: Open Looker Studio β†’ https://lookerstudio.google.com/")
    print(f"  1. Click 'Create' β†’ 'Report'")
    print(f"  2. Click 'Add Data' β†’ 'BigQuery'")
    print(f"  3. Select your project β†’ {dataset_id} β†’ choose a view")
    print(f"  4. For each view, create the corresponding chart:")
    print(f"")
    print(f"  CHART 1: Buyer Risk Leaderboard")
    print(f"    View: buyer_risk_summary")
    print(f"    Chart: Bar chart")
    print(f"    Dimension: buyer_id")
    print(f"    Metric: risk_score (sorted DESC, limit 20)")
    print(f"")
    print(f"  CHART 2: Country Risk Over Time")
    print(f"    View: country_risk_trend")
    print(f"    Chart: Time series (line chart)")
    print(f"    Dimension: month")
    print(f"    Metric: composite_risk_index (AVG)")
    print(f"    Breakdown: country")
    print(f"")
    print(f"  CHART 3: HS-code Exposure Breakdown")
    print(f"    View: shipment_outcomes_by_hs_code")
    print(f"    Chart: Stacked bar chart")
    print(f"    Dimension: product_category")
    print(f"    Metrics: total_value_usd")


def main():
    parser = argparse.ArgumentParser(description="ExportGuard BigQuery Setup")
    parser.add_argument("--dataset", default="exportguard", help="BigQuery dataset name")
    args = parser.parse_args()

    if not check_credentials():
        sys.exit(1)

    setup_bigquery(args.dataset)


if __name__ == "__main__":
    main()