diff --git a/api/app/services/sqlite_service.py b/api/app/services/sqlite_service.py index da209d4..80067d7 100644 --- a/api/app/services/sqlite_service.py +++ b/api/app/services/sqlite_service.py @@ -1440,6 +1440,36 @@ async def update_partner_mismatch_batch(updates: list) -> None: await db.close() +async def clear_stale_partner_mismatches_no_cui(exclude_numbers: set) -> int: + """Clear partner_mismatch=1 for orders with cod_fiscal_gomag=NULL that are NOT in the + current sync batch. These were flagged by old code (before the no-CUI fix) and will + never self-correct because they fall outside the active sync window. + Returns number of rows cleared. + """ + db = await get_sqlite() + try: + if exclude_numbers: + placeholders = ",".join("?" * len(exclude_numbers)) + sql = f""" + UPDATE orders SET partner_mismatch = 0, updated_at = datetime('now') + WHERE partner_mismatch = 1 + AND cod_fiscal_gomag IS NULL + AND order_number NOT IN ({placeholders}) + """ + await db.execute(sql, list(exclude_numbers)) + else: + await db.execute(""" + UPDATE orders SET partner_mismatch = 0, updated_at = datetime('now') + WHERE partner_mismatch = 1 AND cod_fiscal_gomag IS NULL + """) + await db.commit() + cursor = await db.execute("SELECT changes()") + row = await cursor.fetchone() + return row[0] if row else 0 + finally: + await db.close() + + async def update_partner_resync_data(order_number: str, data: dict) -> None: """Update partner fields + clear partner_mismatch after a successful resync.""" db = await get_sqlite() diff --git a/api/app/services/sync_service.py b/api/app/services/sync_service.py index 64f5952..877008a 100644 --- a/api/app/services/sync_service.py +++ b/api/app/services/sync_service.py @@ -641,11 +641,12 @@ async def run_sync(id_pol: int = None, id_sectie: int = None, run_id: str = None def _strip_ro(cf): if not cf: return "" - return re.sub(r'^RO', '', cf.strip().upper()) + # Strip optional "RO" prefix + any surrounding whitespace + return re.sub(r'^RO\s*', '', cf.strip().upper()).strip() is_mismatch = False - if new_data["is_pj"] and not stored_cf: - is_mismatch = True # PF→PJ + if new_data["is_pj"] and new_cf and not stored_cf: + is_mismatch = True # PF→PJ (doar dacă are CUI — fără CUI nu putem confirma) elif not new_data["is_pj"] and stored_cf: is_mismatch = True # PJ→PF elif new_data["is_pj"] and stored_cf and _strip_ro(new_cf) != _strip_ro(stored_cf): @@ -657,17 +658,28 @@ async def run_sync(id_pol: int = None, id_sectie: int = None, run_id: str = None await sqlite_service.update_partner_mismatch_batch(mismatch_updates) + # Clear stale mismatches for orders outside the current sync window + # that have no CUI stored (flagged by old code before the no-CUI fix) + current_batch_numbers = {o.number for o in already_in_roa} + cleared = await sqlite_service.clear_stale_partner_mismatches_no_cui(current_batch_numbers) + if cleared: + logger.info(f"Partner mismatch: cleared {cleared} stale no-CUI flags from previous sync window") + # Auto-resync uninvoiced orders with partner mismatch (max 5/cycle) MAX_PARTNER_RESYNC_PER_CYCLE = 5 + total_mismatched = sum(1 for v in mismatch_map.values() if v == 1) + logger.info(f"Partner mismatch detection: {len(already_in_roa)} orders checked, {total_mismatched} mismatches found") mismatched_uninvoiced = [ o for o in already_in_roa if mismatch_map.get(o.number) == 1 and not stored_partner_data.get(o.number, {}).get("factura_numar") ][:MAX_PARTNER_RESYNC_PER_CYCLE] + logger.info(f"Partner auto-resync: {len(mismatched_uninvoiced)} uninvoiced orders queued") if mismatched_uninvoiced: resync_ok = 0 for _order in mismatched_uninvoiced: + logger.info(f"Partner resync attempt: #{_order.number}") try: await _resync_partner_for_order( order=_order, @@ -676,6 +688,7 @@ async def run_sync(id_pol: int = None, id_sectie: int = None, run_id: str = None run_id=run_id, ) resync_ok += 1 + logger.info(f"Partner resync success: #{_order.number}") except Exception as _e: _log_line(run_id, f"#{_order.number} EROARE resync partener: {_e}") logger.error(f"Partner resync error for {_order.number}: {_e}") @@ -1310,9 +1323,14 @@ async def _resync_partner_for_order(order, stored: dict, app_settings: dict, run resync_result = await asyncio.to_thread(_do_resync) if resync_result.get("same_partner"): - await sqlite_service.update_partner_mismatch_batch([ - {"order_number": order_number, "partner_mismatch": 0} - ]) + # Update cod_fiscal_gomag so next detection doesn't re-flag this order + await sqlite_service.update_partner_resync_data(order_number, { + "id_partener": resync_result["new_partner_id"], + "cod_fiscal_gomag": cod_fiscal_override or new_partner_data["cod_fiscal"], + "cod_fiscal_roa": None, + "denumire_roa": stored.get("denumire_roa"), + "partner_mismatch": 0, + }) _log_line(run_id, f"#{order_number} RESYNC: partener neschimbat, mismatch cleared") else: new_partner_id = resync_result["new_partner_id"]