added error log and bug fixes
This commit is contained in:
parent
468078a015
commit
49aad69efb
|
|
@ -1300,7 +1300,7 @@ def load_items_from_invoices(date_from, date_to, max_count=200, offset=0):
|
||||||
|
|
||||||
for item in items:
|
for item in items:
|
||||||
item_name = item.get('productName', '')
|
item_name = item.get('productName', '')
|
||||||
item_code = item.get('itemId', '') or f"CODE-{serial_number}-{processed_count}"
|
item_code = item.get('itemId', '') or serial_number
|
||||||
|
|
||||||
# Skip empty items
|
# Skip empty items
|
||||||
if not item_name:
|
if not item_name:
|
||||||
|
|
@ -2252,39 +2252,35 @@ def import_invoice_with_mapping(invoice_data, purchase_order_name=None, schedule
|
||||||
'message': 'No active E-Taxes settings found'
|
'message': 'No active E-Taxes settings found'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create mapping dictionaries
|
# Create mapping dictionaries - ИСПРАВЛЕНО: по ID документов
|
||||||
item_mappings = {}
|
item_mappings = {}
|
||||||
for mapping in settings.item_mappings:
|
for mapping in settings.item_mappings:
|
||||||
# mapping.etaxes_item_name содержит name документа E-Taxes Item
|
|
||||||
if mapping.etaxes_item_name and mapping.erp_item:
|
if mapping.etaxes_item_name and mapping.erp_item:
|
||||||
item_mappings[mapping.etaxes_item_name] = mapping.erp_item
|
item_mappings[mapping.etaxes_item_name] = mapping.erp_item
|
||||||
|
|
||||||
party_mappings = {}
|
party_mappings = {}
|
||||||
for mapping in settings.party_mappings:
|
for mapping in settings.party_mappings:
|
||||||
if mapping.etaxes_party_name and mapping.erp_party:
|
if mapping.etaxes_party_name and mapping.erp_party:
|
||||||
|
# Ключ остается по имени и TIN, но значение - это erp_party
|
||||||
key = f"{mapping.etaxes_party_name.lower()}|{mapping.etaxes_tax_id.lower() if mapping.etaxes_tax_id else ''}"
|
key = f"{mapping.etaxes_party_name.lower()}|{mapping.etaxes_tax_id.lower() if mapping.etaxes_tax_id else ''}"
|
||||||
party_mappings[key] = (mapping.erp_party, mapping.party_type)
|
party_mappings[key] = (mapping.erp_party, mapping.party_type)
|
||||||
|
|
||||||
unit_mappings = {}
|
unit_mappings = {}
|
||||||
for mapping in settings.unit_mappings:
|
for mapping in settings.unit_mappings:
|
||||||
if mapping.etaxes_unit_name and mapping.erp_unit:
|
if mapping.etaxes_unit_name and mapping.erp_unit:
|
||||||
# mapping.etaxes_unit_name содержит name документа E-Taxes Unit
|
|
||||||
unit_mappings[mapping.etaxes_unit_name] = mapping.erp_unit
|
unit_mappings[mapping.etaxes_unit_name] = mapping.erp_unit
|
||||||
|
|
||||||
# Get default warehouse
|
# Get default warehouse
|
||||||
default_warehouse = warehouse
|
default_warehouse = warehouse
|
||||||
|
|
||||||
if not default_warehouse:
|
if not default_warehouse:
|
||||||
# If warehouse not specified, try to get from settings
|
|
||||||
if hasattr(settings, 'default_warehouse') and settings.default_warehouse:
|
if hasattr(settings, 'default_warehouse') and settings.default_warehouse:
|
||||||
default_warehouse = settings.default_warehouse
|
default_warehouse = settings.default_warehouse
|
||||||
else:
|
else:
|
||||||
# If warehouse not specified in settings, try to get default warehouse for company
|
|
||||||
company = frappe.defaults.get_user_default('Company')
|
company = frappe.defaults.get_user_default('Company')
|
||||||
if company:
|
if company:
|
||||||
default_warehouse = frappe.db.get_value('Company', company, 'default_warehouse')
|
default_warehouse = frappe.db.get_value('Company', company, 'default_warehouse')
|
||||||
|
|
||||||
# If still no warehouse, take first active warehouse
|
|
||||||
if not default_warehouse:
|
if not default_warehouse:
|
||||||
warehouses = frappe.get_all('Warehouse',
|
warehouses = frappe.get_all('Warehouse',
|
||||||
filters={'is_group': 0, 'disabled': 0},
|
filters={'is_group': 0, 'disabled': 0},
|
||||||
|
|
@ -2293,7 +2289,6 @@ def import_invoice_with_mapping(invoice_data, purchase_order_name=None, schedule
|
||||||
if warehouses:
|
if warehouses:
|
||||||
default_warehouse = warehouses[0].name
|
default_warehouse = warehouses[0].name
|
||||||
|
|
||||||
# Check warehouse existence
|
|
||||||
if not default_warehouse:
|
if not default_warehouse:
|
||||||
return {
|
return {
|
||||||
'success': False,
|
'success': False,
|
||||||
|
|
@ -2304,30 +2299,49 @@ def import_invoice_with_mapping(invoice_data, purchase_order_name=None, schedule
|
||||||
if purchase_order_name:
|
if purchase_order_name:
|
||||||
po = frappe.get_doc('Purchase Order', purchase_order_name)
|
po = frappe.get_doc('Purchase Order', purchase_order_name)
|
||||||
else:
|
else:
|
||||||
# Create new Purchase Order
|
|
||||||
po = frappe.new_doc('Purchase Order')
|
po = frappe.new_doc('Purchase Order')
|
||||||
|
|
||||||
# Set supplier
|
# Set supplier - ИСПРАВЛЕНО: поиск через E-Taxes Parties
|
||||||
sender = invoice_data.get('sender', {})
|
sender = invoice_data.get('sender', {})
|
||||||
sender_key = f"{sender.get('name', '').lower()}|{sender.get('tin', '').lower()}"
|
sender_name = sender.get('name', '')
|
||||||
|
sender_tin = sender.get('tin', '')
|
||||||
|
|
||||||
if sender_key in party_mappings and party_mappings[sender_key][0]:
|
# Ищем E-Taxes Parties документ
|
||||||
po.supplier = party_mappings[sender_key][0]
|
supplier_found = False
|
||||||
else:
|
if sender_name and sender_tin:
|
||||||
|
etaxes_parties = frappe.get_all('E-Taxes Parties',
|
||||||
|
filters={
|
||||||
|
'etaxes_party_name': sender_name,
|
||||||
|
'etaxes_tax_id': sender_tin
|
||||||
|
},
|
||||||
|
fields=['name'],
|
||||||
|
limit=1)
|
||||||
|
|
||||||
|
if etaxes_parties:
|
||||||
|
etaxes_party_name = etaxes_parties[0].name
|
||||||
|
# Ищем маппинг для этого документа
|
||||||
|
for mapping in settings.party_mappings:
|
||||||
|
if (mapping.etaxes_party_name == sender_name and
|
||||||
|
mapping.etaxes_tax_id == sender_tin and
|
||||||
|
mapping.erp_party):
|
||||||
|
po.supplier = mapping.erp_party
|
||||||
|
supplier_found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not supplier_found:
|
||||||
return {
|
return {
|
||||||
'success': False,
|
'success': False,
|
||||||
'unmatched_parties': [{
|
'unmatched_parties': [{
|
||||||
'name': sender.get('name', ''),
|
'name': sender_name,
|
||||||
'tin': sender.get('tin', ''),
|
'tin': sender_tin,
|
||||||
'type': 'Sender'
|
'type': 'Sender'
|
||||||
}],
|
}],
|
||||||
'message': f'No mapping found for supplier: {sender.get("name", "")}'
|
'message': f'No mapping found for supplier: {sender_name}'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Set dates
|
# Set dates
|
||||||
po.transaction_date = frappe.utils.today()
|
po.transaction_date = frappe.utils.today()
|
||||||
|
|
||||||
# Get date from invoice or parameter if specified
|
|
||||||
if schedule_date:
|
if schedule_date:
|
||||||
po.schedule_date = schedule_date
|
po.schedule_date = schedule_date
|
||||||
elif invoice_data.get("creationDate"):
|
elif invoice_data.get("creationDate"):
|
||||||
|
|
@ -2341,7 +2355,6 @@ def import_invoice_with_mapping(invoice_data, purchase_order_name=None, schedule
|
||||||
po.title = f"Invoice {invoice_data.get('serialNumber', '')}"
|
po.title = f"Invoice {invoice_data.get('serialNumber', '')}"
|
||||||
po.invoice_serial_number = invoice_data.get("serialNumber") or invoice_data.get("number", "")
|
po.invoice_serial_number = invoice_data.get("serialNumber") or invoice_data.get("number", "")
|
||||||
|
|
||||||
# Clear existing items if need to update them completely
|
|
||||||
if purchase_order_name and invoice_data.get("items"):
|
if purchase_order_name and invoice_data.get("items"):
|
||||||
po.items = []
|
po.items = []
|
||||||
|
|
||||||
|
|
@ -2361,17 +2374,21 @@ def import_invoice_with_mapping(invoice_data, purchase_order_name=None, schedule
|
||||||
# Add items from invoice
|
# Add items from invoice
|
||||||
if invoice_data.get("items"):
|
if invoice_data.get("items"):
|
||||||
for item in invoice_data.get("items", []):
|
for item in invoice_data.get("items", []):
|
||||||
# Подготавливаем данные товара
|
|
||||||
item_name = item.get("productName", "")
|
item_name = item.get("productName", "")
|
||||||
item_code = item.get("itemId", "")
|
item_code = item.get("itemId", "")
|
||||||
|
|
||||||
# ИСПРАВЛЕНО: Ищем соответствие товара
|
# ИСПРАВЛЕНО: Ищем E-Taxes Item по названию товара, затем маппинг по ID документа
|
||||||
# Так как autoname = "field:etaxes_item_name", name документа E-Taxes Item = etaxes_item_name
|
mapped_item = None
|
||||||
# Поэтому проверяем напрямую по item_name в mappings
|
etaxes_items = frappe.get_all('E-Taxes Item',
|
||||||
mapped_item = item_mappings.get(item_name)
|
filters={'etaxes_item_name': item_name},
|
||||||
|
fields=['name'],
|
||||||
|
limit=1)
|
||||||
|
|
||||||
|
if etaxes_items:
|
||||||
|
etaxes_item_name = etaxes_items[0].name
|
||||||
|
mapped_item = item_mappings.get(etaxes_item_name)
|
||||||
|
|
||||||
if not mapped_item:
|
if not mapped_item:
|
||||||
# Если соответствие не найдено, добавляем в список несопоставленных
|
|
||||||
unmatched_items.append({
|
unmatched_items.append({
|
||||||
'name': item_name,
|
'name': item_name,
|
||||||
'code': item_code
|
'code': item_code
|
||||||
|
|
@ -2383,14 +2400,18 @@ def import_invoice_with_mapping(invoice_data, purchase_order_name=None, schedule
|
||||||
mapped_uom = None
|
mapped_uom = None
|
||||||
|
|
||||||
if unit_name:
|
if unit_name:
|
||||||
# Так как autoname = "field:etaxes_unit_name", name документа E-Taxes Unit = etaxes_unit_name
|
# Ищем E-Taxes Unit по названию единицы, затем маппинг по ID документа
|
||||||
# Поэтому проверяем напрямую по unit_name в mappings
|
etaxes_units = frappe.get_all('E-Taxes Unit',
|
||||||
mapped_uom = unit_mappings.get(unit_name)
|
filters={'etaxes_unit_name': unit_name},
|
||||||
|
fields=['name'],
|
||||||
|
limit=1)
|
||||||
|
|
||||||
|
if etaxes_units:
|
||||||
|
etaxes_unit_name = etaxes_units[0].name
|
||||||
|
mapped_uom = unit_mappings.get(etaxes_unit_name)
|
||||||
|
|
||||||
# Если соответствие единицы не найдено, получаем UOM из товара
|
|
||||||
if not mapped_uom:
|
if not mapped_uom:
|
||||||
if unit_name:
|
if unit_name:
|
||||||
# Добавляем в список несопоставленных единиц
|
|
||||||
unmatched_units.append({
|
unmatched_units.append({
|
||||||
'name': unit_name
|
'name': unit_name
|
||||||
})
|
})
|
||||||
|
|
@ -2400,7 +2421,7 @@ def import_invoice_with_mapping(invoice_data, purchase_order_name=None, schedule
|
||||||
item_doc = frappe.get_doc('Item', mapped_item)
|
item_doc = frappe.get_doc('Item', mapped_item)
|
||||||
mapped_uom = item_doc.stock_uom
|
mapped_uom = item_doc.stock_uom
|
||||||
except:
|
except:
|
||||||
mapped_uom = "Nos" # Fallback
|
mapped_uom = "Nos"
|
||||||
|
|
||||||
# Add position to PO
|
# Add position to PO
|
||||||
po_item = frappe.new_doc("Purchase Order Item")
|
po_item = frappe.new_doc("Purchase Order Item")
|
||||||
|
|
@ -2410,13 +2431,11 @@ def import_invoice_with_mapping(invoice_data, purchase_order_name=None, schedule
|
||||||
|
|
||||||
po_item.item_code = mapped_item
|
po_item.item_code = mapped_item
|
||||||
|
|
||||||
# ИСПРАВЛЕНИЕ: Получаем название и описание из базы данных Item
|
|
||||||
try:
|
try:
|
||||||
item_doc = frappe.get_doc('Item', mapped_item)
|
item_doc = frappe.get_doc('Item', mapped_item)
|
||||||
po_item.item_name = item_doc.item_name
|
po_item.item_name = item_doc.item_name
|
||||||
po_item.description = item_doc.description or item_doc.item_name
|
po_item.description = item_doc.description or item_doc.item_name
|
||||||
except:
|
except:
|
||||||
# Fallback на название из E-Taxes если не удалось получить из базы
|
|
||||||
po_item.item_name = item.get("productName", "")
|
po_item.item_name = item.get("productName", "")
|
||||||
po_item.description = item.get("productName", "")
|
po_item.description = item.get("productName", "")
|
||||||
|
|
||||||
|
|
@ -2424,11 +2443,7 @@ def import_invoice_with_mapping(invoice_data, purchase_order_name=None, schedule
|
||||||
po_item.rate = item.get("pricePerUnit", 0)
|
po_item.rate = item.get("pricePerUnit", 0)
|
||||||
po_item.amount = item.get("cost", 0)
|
po_item.amount = item.get("cost", 0)
|
||||||
po_item.uom = mapped_uom
|
po_item.uom = mapped_uom
|
||||||
|
|
||||||
# IMPORTANT: Set schedule_date for each row
|
|
||||||
po_item.schedule_date = date_to_use
|
po_item.schedule_date = date_to_use
|
||||||
|
|
||||||
# IMPORTANT: Set default warehouse
|
|
||||||
po_item.warehouse = default_warehouse
|
po_item.warehouse = default_warehouse
|
||||||
|
|
||||||
po.append("items", po_item)
|
po.append("items", po_item)
|
||||||
|
|
@ -2450,7 +2465,6 @@ def import_invoice_with_mapping(invoice_data, purchase_order_name=None, schedule
|
||||||
'message': f'No mapping found for {len(unmatched_units)} units'
|
'message': f'No mapping found for {len(unmatched_units)} units'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check that there is at least one element in table
|
|
||||||
if added_items_count == 0:
|
if added_items_count == 0:
|
||||||
frappe.log_error(
|
frappe.log_error(
|
||||||
f"No items were added to PO. Invoice data: {invoice_data}",
|
f"No items were added to PO. Invoice data: {invoice_data}",
|
||||||
|
|
@ -2471,25 +2485,20 @@ def import_invoice_with_mapping(invoice_data, purchase_order_name=None, schedule
|
||||||
if not item.warehouse:
|
if not item.warehouse:
|
||||||
item.warehouse = default_warehouse
|
item.warehouse = default_warehouse
|
||||||
|
|
||||||
# Save again to ensure changes are applied
|
|
||||||
po.save()
|
po.save()
|
||||||
|
|
||||||
# ИЗМЕНЕНИЕ: Создаем E-Taxes Purchase и устанавливаем связь ДО submit'а
|
# Создаем E-Taxes Purchase и устанавливаем связь ДО submit'а
|
||||||
invoice_id = invoice_data.get('id', '')
|
invoice_id = invoice_data.get('id', '')
|
||||||
serial_number = invoice_data.get('serialNumber', '')
|
serial_number = invoice_data.get('serialNumber', '')
|
||||||
sender_name = invoice_data.get('sender', {}).get('name', '') if invoice_data.get('sender') else ''
|
sender_name = invoice_data.get('sender', {}).get('name', '') if invoice_data.get('sender') else ''
|
||||||
total = invoice_data.get('totalAmount', 0) or invoice_data.get('amount', 0)
|
total = invoice_data.get('totalAmount', 0) or invoice_data.get('amount', 0)
|
||||||
|
|
||||||
# Создаем E-Taxes Purchase
|
|
||||||
etaxes_purchase_result = create_etaxes_purchase(invoice_id, date_to_use, sender_name, total)
|
etaxes_purchase_result = create_etaxes_purchase(invoice_id, date_to_use, sender_name, total)
|
||||||
if etaxes_purchase_result and etaxes_purchase_result.get('success'):
|
if etaxes_purchase_result and etaxes_purchase_result.get('success'):
|
||||||
# Устанавливаем поля E-Taxes ДО submit'а
|
|
||||||
po.is_taxes_doc = 1
|
po.is_taxes_doc = 1
|
||||||
po.taxes_doc = etaxes_purchase_result.get('name')
|
po.taxes_doc = etaxes_purchase_result.get('name')
|
||||||
# Сохраняем изменения
|
|
||||||
po.save()
|
po.save()
|
||||||
|
|
||||||
# ИЗМЕНЕНИЕ: Делаем Submit для Purchase Order
|
|
||||||
try:
|
try:
|
||||||
po.submit()
|
po.submit()
|
||||||
frappe.log_error(f"Purchase Order {po.name} submitted successfully", "Import Invoice Success")
|
frappe.log_error(f"Purchase Order {po.name} submitted successfully", "Import Invoice Success")
|
||||||
|
|
@ -2500,11 +2509,9 @@ def import_invoice_with_mapping(invoice_data, purchase_order_name=None, schedule
|
||||||
'message': f'Failed to submit Purchase Order: {str(e)}'
|
'message': f'Failed to submit Purchase Order: {str(e)}'
|
||||||
}
|
}
|
||||||
|
|
||||||
# ИЗМЕНЕНИЕ: Создаем Purchase Invoice
|
|
||||||
try:
|
try:
|
||||||
pi_name = create_purchase_invoice_from_order(po.name)
|
pi_name = create_purchase_invoice_from_order(po.name)
|
||||||
if pi_name:
|
if pi_name:
|
||||||
# Делаем Submit для Purchase Invoice
|
|
||||||
pi = frappe.get_doc("Purchase Invoice", pi_name)
|
pi = frappe.get_doc("Purchase Invoice", pi_name)
|
||||||
pi.submit()
|
pi.submit()
|
||||||
frappe.log_error(f"Purchase Invoice {pi_name} created and submitted successfully", "Import Invoice Success")
|
frappe.log_error(f"Purchase Invoice {pi_name} created and submitted successfully", "Import Invoice Success")
|
||||||
|
|
@ -2516,7 +2523,6 @@ def import_invoice_with_mapping(invoice_data, purchase_order_name=None, schedule
|
||||||
'purchase_invoice': pi_name
|
'purchase_invoice': pi_name
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
# Если не удалось создать Purchase Invoice, всё равно возвращаем успех с Purchase Order
|
|
||||||
return {
|
return {
|
||||||
'success': True,
|
'success': True,
|
||||||
'message': 'Invoice data imported successfully. Purchase Order created, but Purchase Invoice creation failed.',
|
'message': 'Invoice data imported successfully. Purchase Order created, but Purchase Invoice creation failed.',
|
||||||
|
|
@ -2524,7 +2530,6 @@ def import_invoice_with_mapping(invoice_data, purchase_order_name=None, schedule
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
frappe.log_error(f"Error creating or submitting Purchase Invoice: {str(e)}", "Submit PI Error")
|
frappe.log_error(f"Error creating or submitting Purchase Invoice: {str(e)}", "Submit PI Error")
|
||||||
# Если не удалось создать Purchase Invoice, всё равно возвращаем успех с Purchase Order
|
|
||||||
return {
|
return {
|
||||||
'success': True,
|
'success': True,
|
||||||
'message': 'Invoice data imported successfully. Purchase Order created, but Purchase Invoice creation failed.',
|
'message': 'Invoice data imported successfully. Purchase Order created, but Purchase Invoice creation failed.',
|
||||||
|
|
@ -2628,7 +2633,7 @@ def load_items_from_invoices(date_from, date_to, max_count=200, offset=0):
|
||||||
|
|
||||||
for item in items:
|
for item in items:
|
||||||
item_name = item.get('productName', '')
|
item_name = item.get('productName', '')
|
||||||
item_code = item.get('itemId', '') or f"CODE-{serial_number}-{processed_count}"
|
item_code = item.get('itemId', '') or serial_number
|
||||||
|
|
||||||
# Skip empty items
|
# Skip empty items
|
||||||
if not item_name:
|
if not item_name:
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue