90 lines
3.0 KiB
Python
90 lines
3.0 KiB
Python
"""Repair Odoo sale-order references accidentally stored as customer names.
|
|
|
|
v4.9.25.3 fixes the source of the issue. This script repairs rows already
|
|
created by older v4.9.25.x builds where customers.name became S00xxx although
|
|
metadata.raw_customer_payload.partner_name contains the real fiscal customer.
|
|
|
|
Dry-run by default. Use --apply to update rows.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
from typing import Any, Dict, List
|
|
|
|
from sqlalchemy import text
|
|
|
|
from app.db import engine
|
|
|
|
|
|
def _partner_name_from_metadata(metadata: Any) -> str:
|
|
if not isinstance(metadata, dict):
|
|
return ""
|
|
raw = metadata.get("raw_customer_payload")
|
|
if not isinstance(raw, dict):
|
|
return ""
|
|
partner_name = str(raw.get("partner_name") or "").strip()
|
|
if partner_name:
|
|
return partner_name
|
|
partner_id = raw.get("partner_id")
|
|
if isinstance(partner_id, (list, tuple)) and len(partner_id) > 1:
|
|
return str(partner_id[1] or "").strip()
|
|
return ""
|
|
|
|
|
|
def find_rows() -> List[Dict[str, Any]]:
|
|
with engine.begin() as conn:
|
|
rows = conn.execute(text("""
|
|
SELECT id::text, name, tax_id, email, metadata
|
|
FROM customers
|
|
WHERE name ~ '^S[0-9]{4,}'
|
|
AND metadata->>'source_system' = 'odoo'
|
|
ORDER BY updated_at DESC
|
|
""")).mappings().all()
|
|
result: List[Dict[str, Any]] = []
|
|
for row in rows:
|
|
partner_name = _partner_name_from_metadata(row.get("metadata"))
|
|
if partner_name and not partner_name.upper().startswith("S00"):
|
|
data = dict(row)
|
|
data["new_name"] = partner_name
|
|
result.append(data)
|
|
return result
|
|
|
|
|
|
def apply(rows: List[Dict[str, Any]]) -> int:
|
|
updated = 0
|
|
with engine.begin() as conn:
|
|
for row in rows:
|
|
conn.execute(text("""
|
|
UPDATE customers
|
|
SET name = :new_name,
|
|
metadata = COALESCE(metadata, '{}'::jsonb) || jsonb_build_object(
|
|
'odoo_sale_order_name_repaired', true,
|
|
'previous_customer_name', CAST(:old_name AS TEXT)
|
|
),
|
|
updated_at = now()
|
|
WHERE id = CAST(:id AS UUID)
|
|
"""), {"id": row["id"], "old_name": row["name"], "new_name": row["new_name"]})
|
|
updated += 1
|
|
return updated
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(description="Repair Odoo S00xxx customer names.")
|
|
parser.add_argument("--apply", action="store_true", help="Apply updates. Default is dry-run.")
|
|
args = parser.parse_args()
|
|
|
|
rows = find_rows()
|
|
print(f"Clientes Odoo com nome S00xxx reparáveis: {len(rows)}")
|
|
for row in rows[:50]:
|
|
print(f"- {row['name']} -> {row['new_name']} | NIF {row.get('tax_id') or '-'} | email {row.get('email') or '-'}")
|
|
if len(rows) > 50:
|
|
print(f"... mais {len(rows)-50}")
|
|
if not args.apply:
|
|
print("Dry-run. Para aplicar: repetir com --apply")
|
|
return
|
|
print(f"Atualizados: {apply(rows)}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|