#!/usr/bin/env python3 """ Script de création directe de factures pour Odoo 17 Crée les factures directement via le modèle account.move """ import xmlrpc.client from datetime import datetime # Configuration url = 'http://localhost:8069' db = 'covoiturage_db' username = 'admin' password = 'admin' # Connexion à Odoo print("🔌 Connexion à Odoo...") common = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(url)) uid = common.authenticate(db, username, password, {}) if not uid: print("❌ Erreur: Impossible de se connecter à Odoo") exit(1) print(f"✅ Connecté en tant qu'utilisateur ID: {uid}\n") models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url)) print("="*60) print("GÉNÉRATION DIRECTE DES FACTURES - ODOO 17") print("="*60) # Récupérer les commandes confirmées print("\n🔍 Recherche des commandes confirmées...") orders = models.execute_kw(db, uid, password, 'sale.order', 'search_read', [[('state', 'in', ['sale', 'done'])]], {'fields': ['name', 'partner_id', 'amount_total', 'date_order'], 'limit': 10}) # Limiter à 10 pour tester if not orders: print(" ℹ️ Aucune commande confirmée") exit(0) print(f" ✓ {len(orders)} commande(s) trouvée(s)\n") # Récupérer le journal de vente journals = models.execute_kw(db, uid, password, 'account.journal', 'search_read', [[('type', '=', 'sale')]], {'fields': ['name'], 'limit': 1}) if not journals: print("❌ Erreur: Aucun journal de vente trouvé") exit(1) journal_id = journals[0]['id'] print(f"📒 Journal de vente: {journals[0]['name']} (ID: {journal_id})\n") # Créer les factures nb_created = 0 nb_errors = 0 for order in orders: print(f"📝 Commande {order['name']}...") print(f" Client: {order['partner_id'][1]}") print(f" Montant: {order['amount_total']}€") try: # Vérifier si la facture existe déjà existing_invoice = models.execute_kw(db, uid, password, 'account.move', 'search', [[('ref', '=', order['name']), ('move_type', '=', 'out_invoice')]]) if existing_invoice: print(f" ℹ️ Facture déjà existante\n") continue # Récupérer les lignes de commande order_lines = models.execute_kw(db, uid, password, 'sale.order.line', 'search_read', [[('order_id', '=', order['id'])]], {'fields': ['product_id', 'product_uom_qty', 'price_unit', 'tax_id']}) if not order_lines: print(f" ⚠️ Pas de lignes de commande\n") continue # Préparer les lignes de facture invoice_lines = [] for line in order_lines: # Récupérer le compte de revenu du produit product = models.execute_kw(db, uid, password, 'product.product', 'read', [[line['product_id'][0]]], {'fields': ['property_account_income_id', 'categ_id']}) if product and product[0].get('property_account_income_id'): account_id = product[0]['property_account_income_id'][0] else: # Utiliser le compte de revenu par défaut de la catégorie accounts = models.execute_kw(db, uid, password, 'account.account', 'search', [[('code', 'like', '707%')]], {'limit': 1}) if accounts: account_id = accounts[0] else: print(f" ⚠️ Compte comptable introuvable\n") continue invoice_line = { 'product_id': line['product_id'][0], 'name': line['product_id'][1], 'quantity': line['product_uom_qty'], 'price_unit': line['price_unit'], 'account_id': account_id, } # Ajouter les taxes si présentes if line.get('tax_id'): invoice_line['tax_ids'] = [(6, 0, line['tax_id'])] invoice_lines.append((0, 0, invoice_line)) # Créer la facture invoice_data = { 'partner_id': order['partner_id'][0], 'move_type': 'out_invoice', 'invoice_date': datetime.now().strftime('%Y-%m-%d'), 'invoice_origin': order['name'], 'ref': order['name'], 'journal_id': journal_id, 'invoice_line_ids': invoice_lines, } invoice_id = models.execute_kw(db, uid, password, 'account.move', 'create', [invoice_data]) # Lire les infos de la facture invoice_info = models.execute_kw(db, uid, password, 'account.move', 'read', [[invoice_id]], {'fields': ['name', 'state', 'amount_total']}) print(f" ✅ Facture créée: {invoice_info[0]['name']}") print(f" État: {invoice_info[0]['state']}") print(f" Montant: {invoice_info[0]['amount_total']}€") # Valider la facture try: models.execute_kw(db, uid, password, 'account.move', 'action_post', [[invoice_id]]) print(f" ✅ Facture validée et comptabilisée") nb_created += 1 except Exception as e: print(f" ⚠️ Validation impossible: {str(e)[:60]}") except Exception as e: print(f" ❌ Erreur: {str(e)[:100]}") nb_errors += 1 print() # Statistiques finales print("="*60) print("📊 STATISTIQUES FINALES") print("="*60) nb_invoices = models.execute_kw(db, uid, password, 'account.move', 'search_count', [[('move_type', '=', 'out_invoice')]]) nb_posted = models.execute_kw(db, uid, password, 'account.move', 'search_count', [[('move_type', '=', 'out_invoice'), ('state', '=', 'posted')]]) print(f"📄 Factures totales: {nb_invoices}") print(f" - Créées maintenant: {nb_created}") print(f" - Validées: {nb_posted}") print(f" - Erreurs: {nb_errors}") invoices = models.execute_kw(db, uid, password, 'account.move', 'search_read', [[('move_type', '=', 'out_invoice'), ('state', '=', 'posted')]], {'fields': ['amount_total']}) ca_facture = sum([inv['amount_total'] for inv in invoices]) print(f"💰 CA facturé: {ca_facture:.2f}€") print("\n" + "="*60) print("✅ FACTURATION TERMINÉE!") print("="*60)