diff --git a/check_run/check_run/doctype/check_run/check_run.js b/check_run/check_run/doctype/check_run/check_run.js index aabfd4e8..0ba6cbc4 100644 --- a/check_run/check_run/doctype/check_run/check_run.js +++ b/check_run/check_run/doctype/check_run/check_run.js @@ -21,6 +21,17 @@ frappe.ui.form.on('Check Run', { }, refresh: frm => { frm.layout.show_message('') + frm.trigger('update_primary_action') + if (frm.doc.__onload && frm.doc.__onload.errors) { + frm.set_intro(__('This Check Run has errors, click to view.'), 'red') + $('#check-run-error') + .off() + .on('click', e => { + frappe.route_options = { method: ['like', `%${frm.doc.name}%`] } + frappe.set_route('list', 'Error Log') + e.stopPropagation() + }) + } settings_button(frm) permit_first_user(frm) get_defaults(frm) @@ -29,7 +40,6 @@ frappe.ui.form.on('Check Run', { frappe.realtime.on('reload', message => { frm.reload_doc() }) - if (frm.is_new()) { get_balance(frm) } @@ -45,6 +55,10 @@ frappe.ui.form.on('Check Run', { onload_post_render: frm => { frm.page.wrapper.find('.layout-side-section').hide() permit_first_user(frm) + frm.trigger('update_primary_action') + $(frm.wrapper).on('dirty', () => { + frm.trigger('update_primary_action') + }) }, end_date: frm => { get_entries(frm) @@ -75,6 +89,22 @@ frappe.ui.form.on('Check Run', { bank_account: frm => { get_balance(frm) }, + process_check_run: frm => { + frm.layout.show_message('') + frm.doc.status = 'Submitting' + frm.page.set_indicator(__('Submitting'), 'orange') + frm.disable_form() + $(frm.$check_run).css({ 'pointer-events': 'none' }) + frappe.xcall('check_run.check_run.doctype.check_run.check_run.process_check_run', { docname: frm.doc.name }) + }, + update_primary_action: frm => { + frm.disable_save() + if (frm.is_dirty()) { + frm.enable_save() + } else if (frm.doc.status === 'Draft') { + frm.page.set_primary_action(__('Process Check Run'), () => frm.trigger('process_check_run')) + } + }, }) function get_balance(frm) { diff --git a/check_run/check_run/doctype/check_run/check_run.py b/check_run/check_run/doctype/check_run/check_run.py index a708e0a5..43fdca86 100644 --- a/check_run/check_run/doctype/check_run/check_run.py +++ b/check_run/check_run/doctype/check_run/check_run.py @@ -36,6 +36,9 @@ def onload(self): settings = get_check_run_settings(self) if not settings: self.set_onload('settings_missing', True) + errors = frappe.get_all('Error Log', {'method': ['like', f"%{self.name}%"]}) + if errors and self.docstatus == 0: + self.set_onload('errors', True) def validate(self): self.set_status() @@ -125,37 +128,37 @@ def validate_last_check_number(self, check_number=None): frappe.throw(f'Initial Check Number cannot be lower than the last used check number {account_check_number} for {self.bank_account}') @frappe.whitelist() - def before_submit(self): + def process_check_run(self): + self.status = 'Submitting' transactions = self.transactions transactions = json.loads(transactions) if len(transactions) < 1: - frappe.throw("You must select at least one Invoice to pay.") + frappe.throw(frappe._("You must select at least one Invoice to pay.")) self.print_count = 0 if self.ach_only().ach_only: self.initial_check_number = "" self.final_check_number = "" + frappe.enqueue_doc(self.doctype, self.name, "_process_check_run", save=True, queue="short", timeout=3600) - if len(transactions) < 25: - self._before_submit() - else: - self.status = 'Submitting' - frappe.enqueue_doc(self.doctype, self.name, "_before_submit", save=True, queue="short", timeout=3600) - - def _before_submit(self, save=False): + def _process_check_run(self, save=False): + savepoint = "process_check_run" + frappe.db.savepoint(savepoint) try: transactions = self.transactions transactions = json.loads(transactions) transactions = sorted([frappe._dict(item) for item in transactions if item.get("pay")], key=lambda x: x.party) _transactions = self.create_payment_entries(transactions) - - self.db_set('transactions', json.dumps(_transactions)) - self.db_set('status', 'Submitted') - if self.final_check_number: - frappe.db.set_value('Bank Account', self.bank_account, 'check_number', self.final_check_number) - frappe.db.commit() - frappe.publish_realtime('reload', '{}', doctype=self.doctype, docname=self.name) except Exception as e: - frappe.log_error(title=f"{self.name} Check Run Error", message=e) + frappe.db.rollback(savepoint="process_check_run") + raise e + + self.transactions = json.dumps(_transactions) + self.set_status('Submitted') + self.save() + self.submit() + if self.final_check_number: + frappe.db.set_value('Bank Account', self.bank_account, 'check_number', self.final_check_number) + frappe.publish_realtime('reload', '{}', doctype=self.doctype, docname=self.name) def build_nacha_file(self, settings=None): electronic_mop = frappe.get_all('Mode of Payment', {'type': 'Electronic', 'enabled': 1}, 'name', pluck="name") @@ -168,7 +171,6 @@ def build_nacha_file(self, settings=None): ach_file.seek(0) return ach_file - @frappe.whitelist() def ach_only(self): transactions = json.loads(self.transactions) if self.transactions else [] @@ -263,8 +265,14 @@ def create_payment_entries(self, transactions): pe.paid_amount = total_amount pe.base_paid_amount = total_amount pe.base_grand_total = total_amount - pe.save() - pe.submit() + try: + pe.save() + pe.submit() + except Exception as e: + frappe.db.rollback() + frappe.log_error(title=f"{self.name} Check Run Error", message=e) + frappe.publish_realtime('reload', '{}', doctype=self.doctype, docname=self.name) + raise e for reference in _references: reference.payment_entry = pe.name _transactions.append(reference) @@ -273,13 +281,12 @@ def create_payment_entries(self, transactions): @frappe.whitelist() def increment_print_count(self, reprint_check_number=None): - self.load_from_db() + print('render checks') frappe.enqueue_doc(self.doctype, self.name, 'render_check_pdf', reprint_check_number=reprint_check_number, queue='short', now=True) @frappe.whitelist() def render_check_pdf(self, reprint_check_number=None): - self.load_from_db() self.print_count = self.print_count + 1 self.set_status('Submitted') if not frappe.db.exists('File', 'Home/Check Run'): @@ -404,7 +411,7 @@ def get_entries(doc): .where(purchase_invoices.docstatus == 1) .where(purchase_invoices.credit_to == pay_to_account) .where(purchase_invoices.due_date <= end_date) - .where(Coalesce(purchase_invoices.release_date, datetime.date(1900, 1, 1)) <= end_date) + .where(Coalesce(purchase_invoices.release_date, datetime.date(1900, 1, 1)) < end_date) ) # Build expense claims query @@ -492,7 +499,6 @@ def get_entries(doc): }, as_dict=True) for transaction in transactions: if settings and settings.pre_check_overdue_items: - print(transaction.due_date, doc.posting_date) if transaction.due_date < doc.posting_date: transaction.pay = 1 if transaction.doctype == 'Journal Entry': @@ -644,4 +650,10 @@ def ach_only(docname): if not frappe.db.exists('Check Run', docname): return {'ach_only': False, 'checks_only': False} cr = frappe.get_doc('Check Run', docname) - return cr.ach_only() \ No newline at end of file + return cr.ach_only() + + +@frappe.whitelist() +def process_check_run(docname): + doc = frappe.get_doc('Check Run', docname) + doc.process_check_run() diff --git a/check_run/test_setup.py b/check_run/test_setup.py index f9311bef..e4c34384 100644 --- a/check_run/test_setup.py +++ b/check_run/test_setup.py @@ -97,105 +97,108 @@ def before_test(): }), ] -employees = [('Wilmer Larson', - 'Male', - '1977-03-06', - '2019-04-12', - '20 Gaven Path', - 'Spokane', - 'NV', - '66308'), +employees = [ + ('Wilmer Larson', + 'Male', + '1977-03-06', + '2019-04-12', + '20 Gaven Path', + 'Spokane', + 'NV', + '66308'), ('Shanel Finley', - 'Female', - '1984-04-23', - '2019-07-04', - '1070 Ulloa Green', - 'DeKalb', - 'PA', - '30474'), + 'Female', + '1984-04-23', + '2019-07-04', + '1070 Ulloa Green', + 'DeKalb', + 'PA', + '30474'), ('Camellia Phelps', - 'Female', - '1980-07-06', - '2019-07-28', - '787 Sotelo Arcade', - 'Stockton', - 'CO', - '14860'), + 'Female', + '1980-07-06', + '2019-07-28', + '787 Sotelo Arcade', + 'Stockton', + 'CO', + '14860'), ('Michale Mitchell', - 'Male', - '1984-06-29', - '2020-01-12', - '773 Icehouse Road', - 'West Sacramento', - 'VT', - '24355'), + 'Male', + '1984-06-29', + '2020-01-12', + '773 Icehouse Road', + 'West Sacramento', + 'VT', + '24355'), ('Sharilyn Romero', - 'Female', - '1998-04-22', - '2020-03-20', - '432 Dudley Ranch', - 'Clovis', - 'WA', - '97159'), + 'Female', + '1998-04-22', + '2020-03-20', + '432 Dudley Ranch', + 'Clovis', + 'WA', + '97159'), ('Doug Buckley', - 'Male', - '1979-06-18', - '2020-09-08', - '771 Battery Caulfield Motorway', - 'Yonkers', - 'VT', - '38125'), + 'Male', + '1979-06-18', + '2020-09-08', + '771 Battery Caulfield Motorway', + 'Yonkers', + 'VT', + '38125'), ('Margarito Wallace', - 'Male', - '1991-08-17', - '2020-11-01', - '639 Brook Park', - 'Terre Haute', - 'OR', - '41704'), + 'Male', + '1991-08-17', + '2020-11-01', + '639 Brook Park', + 'Terre Haute', + 'OR', + '41704'), ('Mckenzie Ashley', - 'Female', - '1997-09-13', - '2021-02-22', - '1119 Hunter Glen', - 'Ormond Beach', - 'MD', - '30864'), + 'Female', + '1997-09-13', + '2021-02-22', + '1119 Hunter Glen', + 'Ormond Beach', + 'MD', + '30864'), ('Merrie Oliver', - 'Other', - '1979-11-08', - '2021-03-11', - '267 Vega Freeway', - 'West Palm Beach', - 'FL', - '24411'), + 'Other', + '1979-11-08', + '2021-03-11', + '267 Vega Freeway', + 'West Palm Beach', + 'FL', + '24411'), ('Naoma Blake', - 'Female', - '1987-07-10', - '2021-06-21', - '649 Conrad Road', - 'Thousand Oaks', - 'CT', - '97929'), + 'Female', + '1987-07-10', + '2021-06-21', + '649 Conrad Road', + 'Thousand Oaks', + 'CT', + '97929'), ('Donnell Fry', - 'Male', - '1994-07-27', - '2021-06-24', - '504 Starr King Canyon', - 'Norwalk', - 'OR', - '46845'), + 'Male', + '1994-07-27', + '2021-06-24', + '504 Starr King Canyon', + 'Norwalk', + 'OR', + '46845'), ('Shalanda Peterson', - 'Female', - '1999-10-04', - '2021-08-01', - '109 Seventh Parkway', - 'Urbana', - 'DE', - '55975')] + 'Female', + '1999-10-04', + '2021-08-01', + '109 Seventh Parkway', + 'Urbana', + 'DE', + '55975') +] def create_test_data(): + setup_accounts() settings = frappe._dict({ 'day': datetime.date(int(frappe.defaults.get_defaults().get('fiscal_year')), 1 ,1), 'company': frappe.defaults.get_defaults().get('company'), @@ -203,14 +206,12 @@ def create_test_data(): {"account_type": "Bank", "company": frappe.defaults.get_defaults().get('company'), "is_group": 0}), }) create_bank_and_bank_account(settings) - set_up_accounts(settings) create_payment_terms_templates(settings) create_suppliers(settings) create_items(settings) create_invoices(settings) config_expense_claim(settings) create_employees(settings) - create_expense_claim(settings) for month in range(1,13): create_payroll_journal_entry(settings) settings.day = settings.day.replace(month=month) @@ -225,9 +226,25 @@ def create_bank_and_bank_account(settings): mop.append('accounts', {'company': settings.company, 'default_account': settings.company_account}) mop.save() - frappe.db.set_value('Mode of Payment', 'Wire Transfer', 'type', 'General') - frappe.db.set_value('Mode of Payment', 'Credit Card', 'type', 'General') - frappe.db.set_value('Mode of Payment', 'Bank Draft', 'type', 'General') + wire_transfer = frappe.get_doc('Mode of Payment', 'Wire Transfer') + wire_transfer.type = 'General' + wire_transfer.append('accounts', {'company': settings.company, 'default_account': settings.company_account}) + wire_transfer.save() + + credit_card = frappe.get_doc('Mode of Payment', 'Credit Card') + credit_card.type = 'General' + credit_card.append('accounts', {'company': settings.company, 'default_account': settings.company_account}) + credit_card.save() + + bank_draft = frappe.get_doc('Mode of Payment', 'Bank Draft') + bank_draft.type = 'General' + bank_draft.append('accounts', {'company': settings.company, 'default_account': settings.company_account}) + bank_draft.save() + + check_mop = frappe.get_doc('Mode of Payment', 'Check') + check_mop.type = 'Bank' + check_mop.append('accounts', {'company': settings.company, 'default_account': settings.company_account}) + check_mop.save() if not frappe.db.exists('Bank', 'Local Bank'): bank = frappe.new_doc('Bank') @@ -260,11 +277,13 @@ def create_bank_and_bank_account(settings): doc.save() doc.submit() -def set_up_accounts(settings): +def setup_accounts(): frappe.rename_doc('Account', '1000 - Application of Funds (Assets) - CFC', '1000 - Assets - CFC', force=True) frappe.rename_doc('Account', '2000 - Source of Funds (Liabilities) - CFC', '2000 - Liabilities - CFC', force=True) frappe.rename_doc('Account', '1310 - Debtors - CFC', '1310 - Accounts Payable - CFC', force=True) frappe.rename_doc('Account', '2110 - Creditors - CFC', '2110 - Accounts Receivable - CFC', force=True) + update_account_number('1110 - Cash - CFC', 'Petty Cash', account_number='1110') + update_account_number('Primary Checking - CFC', 'Primary Checking', account_number='1201') def create_payment_terms_templates(settings): @@ -296,6 +315,7 @@ def create_payment_terms_templates(settings): "credit_days": 14}) doc.save() + def create_suppliers(settings): addresses = frappe._dict({}) for supplier in suppliers + tax_authority: @@ -488,6 +508,7 @@ def config_expense_claim(settings): pta.parent_account = frappe.get_value('Account', {'account_name': 'Indirect Expenses', 'company': settings.company}) pta.save() + def create_employees(settings): for employee_number, employee in enumerate(employees, start=10): emp = frappe.new_doc('Employee') @@ -507,6 +528,7 @@ def create_employees(settings): emp.bank_account = f'{employee_number}12345' emp.save() + def create_expense_claim(settings): cost_center = frappe.get_value('Company', settings.company, 'cost_center') payable_acct = frappe.get_value('Company', settings.company, 'default_payable_account') @@ -564,6 +586,7 @@ def create_expense_claim(settings): ec.save() ec.submit() + def create_payroll_journal_entry(settings): emps = frappe.get_list('Employee', {'company': settings.company}) cost_center = frappe.get_value('Company', settings.company, 'cost_center')