RECORDGOD/shipping_sync.py
2026-06-24 01:05:12 +10:00

81 lines
3.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""Mirror WowPlatter's AusPost flat-rate + zone tables → RecordGod Postgres.
python3 shipping_sync.py | ssh -C root@100.94.195.115 \
'docker exec -i recordgod-db psql -U recordgod -d recordgod -q -v ON_ERROR_STOP=1'
post_flat_rate = service × size/weight bracket → price (Parcel Post / Express). post_zone = postcode range.
Prices use AusPost's 2026-07-01 "own packaging, postage only" rates (the bracket the shop ships records in) —
loaded straight in since RecordGod isn't live before the change. Update RATES below from the next Post Charges
Guide (John's PDF→Gemini path) and re-run.
"""
import re
import pathlib
import sys
import pymysql
WP_CONFIG = "/opt/homebrew/var/www/monsterrobot.localsite/wp-config.php"
SOCK = "/opt/homebrew/var/mysql/mysql.sock"
SCHEMA = """
DROP TABLE IF EXISTS post_flat_rate, post_zone CASCADE;
CREATE TABLE post_flat_rate (service_key text, packaging_type text, size_label text,
weight_min_g int, weight_max_g int, price numeric(10,2));
CREATE TABLE post_zone (postcode_start int, postcode_end int, zone_code text);
CREATE INDEX ON post_flat_rate (service_key, weight_min_g, weight_max_g);
CREATE INDEX ON post_zone (postcode_start, postcode_end);
"""
# Current AusPost rates — own packaging, postage only, by weight (effective 2026-07-01 Post Charges Guide).
RATES = { # service_key -> {size_label: price}
"PARCEL_POST": {"XS": "10.20", "S": "11.70", "M": "16.00", "L": "20.25", "XL": "24.45"},
"EXPRESS_POST": {"XS": "13.20", "S": "15.20", "M": "20.00", "L": "24.75", "XL": "32.95"},
}
FR = ["service_key", "packaging_type", "size_label", "weight_min_g", "weight_max_g", "price"]
ZN = ["postcode_start", "postcode_end", "zone_code"]
def creds():
t = pathlib.Path(WP_CONFIG).read_text()
g = lambda k: re.search(rf"'{k}',\s*'([^']*)'", t).group(1)
return g("DB_NAME"), g("DB_USER"), g("DB_PASSWORD")
def cp(v):
if v is None or v == "":
return r"\N"
return str(v).replace("\\", "\\\\").replace("\t", "\\t").replace("\n", "\\n").replace("\r", "\\r")
def block(out, table, cols, rows):
out.write(f"COPY {table} ({','.join(cols)}) FROM stdin;\n")
for r in rows:
out.write("\t".join(cp(r[c]) for c in cols) + "\n")
out.write("\\.\n\n")
print(f" {table:16} {len(rows):>4}", file=sys.stderr)
def main():
name, user, pw = creds()
my = pymysql.connect(unix_socket=SOCK, user=user, password=pw, database=name,
cursorclass=pymysql.cursors.DictCursor)
c = my.cursor()
P = "wp_rmp_disc_"
out = sys.stdout
out.write(SCHEMA)
c.execute(f"SELECT {','.join(FR)} FROM {P}post_flat_rates") # structure (brackets) from WowPlatter
rows = c.fetchall()
for r in rows: # …prices overridden with the current AusPost ones
new = RATES.get(r["service_key"], {}).get(r["size_label"])
if new is not None:
r["price"] = new
block(out, "post_flat_rate", FR, rows)
c.execute(f"SELECT {','.join(ZN)} FROM {P}post_zones")
block(out, "post_zone", ZN, c.fetchall())
if __name__ == "__main__":
main()