From c6c26d39a3b3e4bff94bccdd03b0e25d2f094ca2 Mon Sep 17 00:00:00 2001 From: esam Date: Tue, 18 Nov 2025 17:01:32 -0500 Subject: [PATCH] migration --- .../migrations/14.3/post-migrate.py | 356 ++++++++++++++++++ 1 file changed, 356 insertions(+) create mode 100644 odex25_purchase/odex25_purchase_coc/migrations/14.3/post-migrate.py diff --git a/odex25_purchase/odex25_purchase_coc/migrations/14.3/post-migrate.py b/odex25_purchase/odex25_purchase_coc/migrations/14.3/post-migrate.py new file mode 100644 index 000000000..bc247738a --- /dev/null +++ b/odex25_purchase/odex25_purchase_coc/migrations/14.3/post-migrate.py @@ -0,0 +1,356 @@ +import logging + +_logger = logging.getLogger(__name__) + + +def migrate(cr, version): + """ + Migrate old CoC data to new structure + """ + from odoo import api, SUPERUSER_ID + + env = api.Environment(cr, SUPERUSER_ID, {}) + + _logger.info("Starting CoC data migration...") + + # Get all old CoC records without lines + cr.execute(""" + SELECT id FROM purchase_coc + WHERE id NOT IN ( + SELECT DISTINCT coc_id FROM purchase_coc_line WHERE coc_id IS NOT NULL + ) + """) + + old_coc_ids = [row[0] for row in cr.fetchall()] + _logger.info(f"Found {len(old_coc_ids)} CoC records to migrate") + + success_count = 0 + error_count = 0 + + for coc_id in old_coc_ids: + savepoint_name = f"coc_migration_{coc_id}" + + try: + cr.execute(f"SAVEPOINT {savepoint_name}") + + coc = env['purchase.coc'].browse(coc_id) + if not coc.exists() or not coc.po_id: + cr.execute(f"RELEASE SAVEPOINT {savepoint_name}") + continue + + _logger.info(f"Migrating CoC {coc.name} (ID: {coc.id})") + cr.execute(""" + SELECT COUNT(*) + FROM purchase_coc + WHERE po_id = %s AND (is_return IS NULL OR is_return = false) + """, (coc.po_id.id,)) + + total_cocs_for_po = cr.fetchone()[0] + is_single_coc = (total_cocs_for_po == 1) + + # التحقق من وجود حقل is_return + cr.execute(""" + SELECT EXISTS ( + SELECT FROM information_schema.columns + WHERE table_name = 'purchase_coc' + AND column_name = 'is_return' + ) + """) + has_is_return = cr.fetchone()[0] + + is_not_return = True + if has_is_return: + cr.execute("SELECT COALESCE(is_return, false) FROM purchase_coc WHERE id = %s", (coc.id,)) + is_not_return = not cr.fetchone()[0] + + + + # Get service lines from PO with qty_received_fake + # التحقق من وجود حقل qty_received_fake أولاً + cr.execute(""" + SELECT EXISTS ( + SELECT FROM information_schema.columns + WHERE table_name = 'purchase_order_line' + AND column_name = 'qty_received_fake' + ) + """) + + has_qty_received_fake = cr.fetchone()[0] + + if has_qty_received_fake: + # استخدام qty_received_fake من البنية القديمة + cr.execute(""" + SELECT pol.id, pol.product_id, pol.name, pol.product_qty, + COALESCE(pol.qty_received, 0) as qty_received, + COALESCE(pol.qty_received_fake, 0) as qty_received_fake, + pol.price_unit, pol.product_uom, pol.date_planned + FROM purchase_order_line pol + JOIN product_product pp ON pol.product_id = pp.id + JOIN product_template pt ON pp.product_tmpl_id = pt.id + WHERE pol.order_id = %s AND pt.type = 'service' + """, (coc.po_id.id,)) + + po_lines = cr.fetchall() + + + else: + + # البنية الجديدة - بدون qty_received_fake + cr.execute(""" + SELECT pol.id, pol.product_id, pol.name, pol.product_qty, + COALESCE(pol.qty_received, 0) as qty_received, + 0 as qty_received_fake, + pol.price_unit, pol.product_uom, pol.date_planned + FROM purchase_order_line pol + JOIN product_product pp ON pol.product_id = pp.id + JOIN product_template pt ON pp.product_tmpl_id = pt.id + WHERE pol.order_id = %s AND pt.type = 'service' + """, (coc.po_id.id,)) + + po_lines = cr.fetchall() + + if not po_lines: + _logger.warning(f"No service lines found for CoC {coc.name}") + cr.execute(f"RELEASE SAVEPOINT {savepoint_name}") + continue + + lines_created = 0 + for line_data in po_lines: + po_line_id, product_id, name, product_qty, qty_received, qty_received_fake, price_unit, product_uom, date_planned = line_data + + po_line = env['purchase.order.line'].browse(po_line_id) + if not po_line.exists(): + continue + + # Calculate received quantities from history + qty_received_total = 0.0 + cr.execute(""" + SELECT EXISTS ( + SELECT FROM information_schema.tables + WHERE table_name = 'purchase_order_line_history' + ) + """) + + if cr.fetchone()[0]: + cr.execute(""" + SELECT COALESCE(SUM(qty_received), 0) + FROM purchase_order_line_history + WHERE po_line_id = %s + """, (po_line_id,)) + history_total = cr.fetchone()[0] or 0.0 + + # استخدام أكبر قيمة بين التاريخ و qty_received + qty_received_total = max(history_total, qty_received) + else: + qty_received_total = qty_received + + qty_remaining = product_qty - qty_received_total + qty_to_receive = qty_received_fake if qty_received_fake > 0 else 0.0 + if is_not_return and is_single_coc: + # ✅ إذا كانت شهادة واحدة وليست إرجاع، استخدم qty_received كـ qty_to_receive + qty_to_receive = qty_received if qty_received > 0 else 0.0 + + # qty_remaining = 0.0 + # qty_received_total = 0.0 + _logger.info( + f"Single CoC detected for PO {coc.po_id.name}: qty_to_receive={qty_to_receive}, qty_remaining={qty_remaining}") + + # qty_remaining = product_qty - qty_received_total + # + # # استخدام qty_received_fake كـ qty_to_receive إذا كانت موجودة + # qty_to_receive = qty_received_fake if qty_received_fake > 0 else 0.0 + + # Create new CoC line + coc_line_vals = { + 'coc_id': coc.id, + 'po_line_id': po_line_id, + 'product_id': product_id, + 'name': name, + 'product_qty': product_qty, + 'qty_ordered': product_qty, + 'qty_received_total': qty_received_total, + 'qty_remaining': max(0, qty_remaining), + 'qty_to_receive': qty_to_receive, # ← استخدام القيمة من qty_received_fake + 'price_unit': price_unit, + 'product_uom': product_uom, + 'partner_id': coc.vendor_id.id if coc.vendor_id else coc.po_id.partner_id.id, + 'date_planned': date_planned, + 'currency_id': coc.po_id.currency_id.id, + 'sub_price_total': price_unit * product_qty, + } + + env['purchase.coc.line'].create(coc_line_vals) + lines_created += 1 + + cr.execute(f"RELEASE SAVEPOINT {savepoint_name}") + _logger.info(f"Successfully migrated CoC {coc.name} with {lines_created} lines") + success_count += 1 + + except Exception as e: + cr.execute(f"ROLLBACK TO SAVEPOINT {savepoint_name}") + _logger.error(f"Error migrating CoC {coc_id}: {str(e)}") + error_count += 1 + continue + + _logger.info(f"CoC data migration completed! Success: {success_count}, Errors: {error_count}") + + + +# # -*- coding: utf-8 -*- +# import logging +# +# _logger = logging.getLogger(__name__) +# +# +# def migrate(cr, version): +# """ +# Migrate old CoC data to new structure +# """ +# from odoo import api, SUPERUSER_ID +# +# env = api.Environment(cr, SUPERUSER_ID, {}) +# +# _logger.info("Starting CoC data migration...") +# +# # Get all old CoC records without lines +# cr.execute(""" +# SELECT id FROM purchase_coc +# WHERE id NOT IN ( +# SELECT DISTINCT coc_id FROM purchase_coc_line WHERE coc_id IS NOT NULL +# ) +# """) +# +# old_coc_ids = [row[0] for row in cr.fetchall()] +# _logger.info(f"Found {len(old_coc_ids)} CoC records to migrate") +# +# success_count = 0 +# error_count = 0 +# +# for coc_id in old_coc_ids: +# savepoint_name = f"coc_migration_{coc_id}" +# +# try: +# cr.execute(f"SAVEPOINT {savepoint_name}") +# +# coc = env['purchase.coc'].browse(coc_id) +# if not coc.exists() or not coc.po_id: +# cr.execute(f"RELEASE SAVEPOINT {savepoint_name}") +# continue +# +# _logger.info(f"Migrating CoC {coc.name} (ID: {coc.id})") +# +# # Get service lines from PO with qty_received_fake +# # التحقق من وجود حقل qty_received_fake أولاً +# cr.execute(""" +# SELECT EXISTS ( +# SELECT FROM information_schema.columns +# WHERE table_name = 'purchase_order_line' +# AND column_name = 'qty_received_fake' +# ) +# """) +# +# has_qty_received_fake = cr.fetchone()[0] +# +# if has_qty_received_fake: +# # استخدام qty_received_fake من البنية القديمة +# cr.execute(""" +# SELECT pol.id, pol.product_id, pol.name, pol.product_qty, +# COALESCE(pol.qty_received, 0) as qty_received, +# COALESCE(pol.qty_received_fake, 0) as qty_received_fake, +# pol.price_unit, pol.product_uom, pol.date_planned +# FROM purchase_order_line pol +# JOIN product_product pp ON pol.product_id = pp.id +# JOIN product_template pt ON pp.product_tmpl_id = pt.id +# WHERE pol.order_id = %s AND pt.type = 'service' +# """, (coc.po_id.id,)) +# +# po_lines = cr.fetchall() +# else: +# # البنية الجديدة - بدون qty_received_fake +# cr.execute(""" +# SELECT pol.id, pol.product_id, pol.name, pol.product_qty, +# COALESCE(pol.qty_received, 0) as qty_received, +# 0 as qty_received_fake, +# pol.price_unit, pol.product_uom, pol.date_planned +# FROM purchase_order_line pol +# JOIN product_product pp ON pol.product_id = pp.id +# JOIN product_template pt ON pp.product_tmpl_id = pt.id +# WHERE pol.order_id = %s AND pt.type = 'service' +# """, (coc.po_id.id,)) +# +# po_lines = cr.fetchall() +# +# if not po_lines: +# _logger.warning(f"No service lines found for CoC {coc.name}") +# cr.execute(f"RELEASE SAVEPOINT {savepoint_name}") +# continue +# +# lines_created = 0 +# for line_data in po_lines: +# po_line_id, product_id, name, product_qty, qty_received, qty_received_fake, price_unit, product_uom, date_planned = line_data +# +# po_line = env['purchase.order.line'].browse(po_line_id) +# if not po_line.exists(): +# continue +# +# # Calculate received quantities from history +# qty_received_total = 0.0 +# cr.execute(""" +# SELECT EXISTS ( +# SELECT FROM information_schema.tables +# WHERE table_name = 'purchase_order_line_history' +# ) +# """) +# +# if cr.fetchone()[0]: +# cr.execute(""" +# SELECT COALESCE(SUM(qty_received), 0) +# FROM purchase_order_line_history +# WHERE po_line_id = %s +# """, (po_line_id,)) +# history_total = cr.fetchone()[0] or 0.0 +# +# # استخدام أكبر قيمة بين التاريخ و qty_received +# qty_received_total = max(history_total, qty_received) +# else: +# qty_received_total = qty_received +# +# qty_remaining = product_qty - qty_received_total +# +# # استخدام qty_received_fake كـ qty_to_receive إذا كانت موجودة +# qty_to_receive = qty_received_fake if qty_received_fake > 0 else 0.0 +# +# # Create new CoC line +# coc_line_vals = { +# 'coc_id': coc.id, +# 'po_line_id': po_line_id, +# 'product_id': product_id, +# 'name': name, +# 'product_qty': product_qty, +# 'qty_ordered': product_qty, +# 'qty_received_total': qty_received_total, +# 'qty_remaining': max(0, qty_remaining), +# 'qty_to_receive': qty_to_receive, # ← استخدام القيمة من qty_received_fake +# 'price_unit': price_unit, +# 'product_uom': product_uom, +# 'partner_id': coc.vendor_id.id if coc.vendor_id else coc.po_id.partner_id.id, +# 'date_planned': date_planned, +# 'currency_id': coc.po_id.currency_id.id, +# 'sub_price_total': price_unit * product_qty, +# } +# +# env['purchase.coc.line'].create(coc_line_vals) +# lines_created += 1 +# +# cr.execute(f"RELEASE SAVEPOINT {savepoint_name}") +# _logger.info(f"Successfully migrated CoC {coc.name} with {lines_created} lines") +# success_count += 1 +# +# except Exception as e: +# cr.execute(f"ROLLBACK TO SAVEPOINT {savepoint_name}") +# _logger.error(f"Error migrating CoC {coc_id}: {str(e)}") +# error_count += 1 +# continue +# +# _logger.info(f"CoC data migration completed! Success: {success_count}, Errors: {error_count}") +#