Release v4928.1.4.2 stable
This commit is contained in:
89
scripts/repair_odoo_sale_order_customer_names.py
Normal file
89
scripts/repair_odoo_sale_order_customer_names.py
Normal file
@@ -0,0 +1,89 @@
|
||||
"""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()
|
||||
Reference in New Issue
Block a user