diff --git a/transaction_parser/parser_benchmark/runner.py b/transaction_parser/parser_benchmark/runner.py index 8f949d7..a4f59a0 100644 --- a/transaction_parser/parser_benchmark/runner.py +++ b/transaction_parser/parser_benchmark/runner.py @@ -156,6 +156,7 @@ def _run_ai_parsing(self, file_content: str, file_name: str) -> dict: document_schema=self.controller.get_schema(), document_data=file_content, file_doc_name=file_name, + company=self.dataset.company, ) self.log.ai_parse_time = flt(default_timer() - start, self.precision) diff --git a/transaction_parser/public/js/transaction_parser_dialog.js b/transaction_parser/public/js/transaction_parser_dialog.js index 1382721..919052f 100644 --- a/transaction_parser/public/js/transaction_parser_dialog.js +++ b/transaction_parser/public/js/transaction_parser_dialog.js @@ -52,6 +52,17 @@ async function create_transaction_parser_dialog(transaction_type, list_view) { default: get_default_country(), reqd: 1, }, + { + fieldtype: "Section Break", + }, + { + fieldname: "company", + label: __("Company"), + fieldtype: "Link", + options: "Company", + default: frappe.defaults.get_user_default("Company"), + reqd: 1, + }, ], primary_action_label: __("Submit"), primary_action(values) { diff --git a/transaction_parser/transaction_parser/__init__.py b/transaction_parser/transaction_parser/__init__.py index abd27da..fb35787 100644 --- a/transaction_parser/transaction_parser/__init__.py +++ b/transaction_parser/transaction_parser/__init__.py @@ -15,7 +15,7 @@ @frappe.whitelist() -def parse(transaction, country, file_url, ai_model=None, page_limit=None): +def parse(transaction, country, file_url, ai_model=None, page_limit=None, company=None): is_enabled() frappe.has_permission(TRANSACTION_MAP[transaction], "create", throw=True) @@ -27,6 +27,7 @@ def parse(transaction, country, file_url, ai_model=None, page_limit=None): file_url=cstr(file_url), ai_model=cstr(ai_model), page_limit=cint(page_limit), + company=cstr(company) if company else None, queue="long", now=frappe.conf.developer_mode, ) diff --git a/transaction_parser/transaction_parser/ai_integration/parser.py b/transaction_parser/transaction_parser/ai_integration/parser.py index a9925e1..bd70cfd 100644 --- a/transaction_parser/transaction_parser/ai_integration/parser.py +++ b/transaction_parser/transaction_parser/ai_integration/parser.py @@ -36,19 +36,27 @@ def parse( document_schema: dict, document_data: str, file_doc_name: str | None = None, + company: str | None = None, ) -> dict: - messages = self._build_messages(document_type, document_schema, document_data) + messages = self._build_messages( + document_type, document_schema, document_data, company + ) self.ai_response = self.send_message( messages=messages, file_doc_name=file_doc_name ) return self.get_content(self.ai_response) def _build_messages( - self, document_type: str, document_schema: dict, document_data: str + self, + document_type: str, + document_schema: dict, + document_data: str, + company: str | None = None, ) -> tuple: """Build the message structure for AI API call.""" + company_info = self._get_company_info(company) if company else "" system_prompt = get_system_prompt(document_schema) - user_prompt = get_user_prompt(document_type, document_data) + user_prompt = get_user_prompt(document_type, document_data, company_info) return ( { @@ -61,6 +69,23 @@ def _build_messages( }, ) + @staticmethod + def _get_company_info(company: str) -> str: + """Build a company context string with name and address if available.""" + from frappe.contacts.doctype.address.address import get_company_address + from frappe.utils import strip_html + + info = f"Company: {company}" + + address = get_company_address(company) + if address and address.company_address_display: + address_text = strip_html(address.company_address_display).strip() + + if address_text: + info += f"\nLocated at: {address_text}" + + return info + def send_message(self, messages: tuple, file_doc_name: str | None = None) -> dict: """Send messages to AI API and handle the response.""" log = self._create_log_entry(file_doc_name) diff --git a/transaction_parser/transaction_parser/ai_integration/prompts.py b/transaction_parser/transaction_parser/ai_integration/prompts.py index 95cf2e0..8fd4d91 100644 --- a/transaction_parser/transaction_parser/ai_integration/prompts.py +++ b/transaction_parser/transaction_parser/ai_integration/prompts.py @@ -34,10 +34,27 @@ def get_system_prompt(document_schema: dict) -> str: {document_schema}""" -def get_user_prompt(document_type: str, document_data: str) -> str: +def get_user_prompt( + document_type: str, document_data: str, company_info: str = "" +) -> str: input_doc_type = INPUT_DOCUMENTS.get(document_type, "document") - return f"""Generate {document_type} for given {input_doc_type} according to above JSON schema. + company_context = "" + if company_info: + if document_type == "Sales Order": + role_hint = "Use this to correctly identify the company as the seller/vendor and the other party as the customer/buyer." + else: + role_hint = "Use this to correctly identify the company as the buyer/recipient and the other party as the vendor/supplier." + + company_context = f""" + +This {input_doc_type} is received by the following company: +{company_info} + +{role_hint} +""" + + return f"""Generate {document_type} for the given {input_doc_type} according to above JSON schema.{company_context} Document data is given below: {document_data}""" diff --git a/transaction_parser/transaction_parser/controllers/transaction.py b/transaction_parser/transaction_parser/controllers/transaction.py index 178ffed..d257331 100644 --- a/transaction_parser/transaction_parser/controllers/transaction.py +++ b/transaction_parser/transaction_parser/controllers/transaction.py @@ -85,6 +85,7 @@ def _parse_file_content( document_schema=schema, document_data=content, file_doc_name=self.file.name, + company=self.company, ) ################################### diff --git a/transaction_parser/transaction_parser/doctype/transaction_parser_party_email/transaction_parser_party_email.json b/transaction_parser/transaction_parser/doctype/transaction_parser_party_email/transaction_parser_party_email.json index c8aab80..72e3372 100644 --- a/transaction_parser/transaction_parser/doctype/transaction_parser_party_email/transaction_parser_party_email.json +++ b/transaction_parser/transaction_parser/doctype/transaction_parser_party_email/transaction_parser_party_email.json @@ -50,4 +50,4 @@ "sort_field": "modified", "sort_order": "DESC", "states": [] -} \ No newline at end of file +} diff --git a/transaction_parser/transaction_parser/overrides/communication.py b/transaction_parser/transaction_parser/overrides/communication.py index 679ae95..6ba0397 100644 --- a/transaction_parser/transaction_parser/overrides/communication.py +++ b/transaction_parser/transaction_parser/overrides/communication.py @@ -13,6 +13,18 @@ def on_update(doc, method=None): if not (settings.enabled and settings.parse_incoming_emails): return + matched_account = next( + ( + row + for row in settings.incoming_email_accounts + if row.to_email in doc.recipients + ), + None, + ) + + if not matched_account: + return + if settings.parse_party_emails: matched_party_config = next( (row for row in settings.party_emails if row.party_email == doc.sender), @@ -41,21 +53,10 @@ def on_update(doc, method=None): settings, default_user, matched_party_config.party, + matched_account.company, ) return - matched_account = next( - ( - row - for row in settings.incoming_email_accounts - if row.to_email in doc.recipients - ), - None, - ) - - if not matched_account: - return - # Attachments are not available when the Communication doc is created. # Next time the doc is updated, we will check for attachments, # and update the flag `is_processed_by_transaction_parser` accordingly.