RECORDGOD/shipping_sync.py
type-two ef4769784f feat: Woo customer sync (non-destructive, in refresh.sh) + AusPost rates mirror & quote calc
customer_woo_sync.py: WooCommerce online customers (wc_customer_lookup+billing) → RecordGod
customer CRM, links-by-email/refresh-by-wp_user_id/insert-new, never clobbers POS rows; added
as refresh.sh step 5 (after the --clean push). shipping_sync.py mirrors disc_post_flat_rates
(+zones) → post_flat_rate/post_zone. /sales/shipping/quote (units|weight_g → 280g/record →
≤5kg parcels → flat rate × parcels, Parcel Post + Express). POS Register '📦 post' quotes the
cart + adds a postage line. AusPost +5% lands 2026-07-01 — re-pull rates then.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 00:55:56 +10:00

69 lines
2.4 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, own packaging).
post_zone = postcode range → zone (kept for future distance/zone pricing; flat rate is weight-only).
NOTE: AusPost rates rise ~+5% on 2026-07-01 — re-pull from the WowPlatter table (PDF→Gemini path) after the update.
"""
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);
"""
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")
block(out, "post_flat_rate", FR, c.fetchall())
c.execute(f"SELECT {','.join(ZN)} FROM {P}post_zones")
block(out, "post_zone", ZN, c.fetchall())
if __name__ == "__main__":
main()