fix: skip mapping creation if document creation fails in Both mode

In "Both" mode, mappings were saved before documents were created,
so a failed document still produced a mapping entry.

Now for "Both" mode: document is created first, and the mapping row
is added only on success. Settings are saved once after all transactions.
"Mappings Only" and "Documents & Reconcile" modes are unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ali 2026-03-16 16:16:20 +04:00
parent 3b44f5a694
commit 2f10fb4aa0
1 changed files with 54 additions and 3 deletions

View File

@ -21,7 +21,7 @@ def create_purpose_mappings(transactions, paid_from=None, paid_to=None, document
try:
txn_list = json.loads(transactions) if isinstance(transactions, str) else transactions
do_mappings = mode in ("Both", "Mappings Only")
do_mappings = mode == "Mappings Only"
do_documents = mode in ("Both", "Documents & Reconcile")
created_mappings = 0
@ -31,11 +31,11 @@ def create_purpose_mappings(transactions, paid_from=None, paid_to=None, document
reconciled = 0
errors = []
needs_settings = do_mappings or mode == "Documents & Reconcile"
needs_settings = do_mappings or do_documents
if needs_settings:
settings = frappe.get_single("Kapital Bank Settings")
if do_mappings:
if mode in ("Both", "Mappings Only"):
existing_purpose = {
(row.purpose_keyword, row.payment_type, (row.currency or "").upper())
for row in settings.transaction_mappings
@ -47,6 +47,7 @@ def create_purpose_mappings(transactions, paid_from=None, paid_to=None, document
if not row.purpose_keyword and row.counterparty and row.payment_type
}
if do_mappings:
# Deduplicate within batch; first occurrence wins for party info
unique_purposes = {}
unique_parties = {}
@ -190,12 +191,62 @@ def create_purpose_mappings(transactions, paid_from=None, paid_to=None, document
"reference_number": txn.get("reference_number") or "",
"message": result.get("error"),
})
# In "Both" mode: add mapping only after successful document creation
if mode == "Both":
purpose = (txn.get("purpose") or "").strip()
party_type = (txn.get("party_type") or "").strip()
party = (txn.get("party") or "").strip()
payment_type = "Pay" if txn.get("drcr") == "D" else "Receive"
bt_name = txn.get("bank_transaction_name")
kb_currency = (frappe.db.get_value("Bank Transaction", bt_name, "kb_currency") or "").strip().upper() if bt_name else ""
is_foreign = kb_currency and kb_currency != "AZN"
if purpose:
purpose_name = _ensure_purpose(purpose)
key = (purpose_name, payment_type, kb_currency)
if key not in existing_purpose:
settings.append("transaction_mappings", {
"purpose_keyword": purpose_name,
"payment_type": payment_type,
"paid_from": paid_from,
"paid_to": paid_to,
"document_type": document_type,
"counterparty_type": party_type or None,
"counterparty": party or None,
"currency": kb_currency or None,
"multi_currency": 1 if is_foreign else 0,
})
existing_purpose.add(key)
created_mappings += 1
elif party:
key = (party_type, party, payment_type, kb_currency)
if key not in existing_party_only:
settings.append("transaction_mappings", {
"purpose_keyword": None,
"payment_type": payment_type,
"paid_from": paid_from,
"paid_to": paid_to,
"document_type": document_type,
"counterparty_type": party_type or None,
"counterparty": party or None,
"currency": kb_currency or None,
"multi_currency": 1 if is_foreign else 0,
})
existing_party_only.add(key)
created_mappings += 1
else:
skipped_no_data += 1
else:
errors.append({
"reference_number": txn.get("reference_number") or "",
"message": result.get("error") or "Unknown error",
})
if mode == "Both" and created_mappings > 0:
settings.save(ignore_permissions=True)
frappe.db.commit()
return {
"success": True,
"created_mappings": created_mappings,