diff --git a/.gitignore b/.gitignore index 9ef7f9fc..766288fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,194 @@ -.DS_Store *.pyc -*.egg-info +*.py~ +*.comp.js +*.DS_Store +locale +.wnf-lang-status *.swp -tags -check_run/docs/current \ No newline at end of file +*.egg-info +dist/ +# build/ +frappe/docs/current +.vscode +node_modules +.kdev4/ +*.kdev4 +*debug.log + +# Not Recommended, but will remove once webpack ready +package-lock.json + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +# build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +.static_storage/ +.media/ +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Typescript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# next.js build output +.next + +# cypress +cypress/screenshots +cypress/videos + +# JetBrains IDEs +.idea/ diff --git a/README.md b/README.md index 9da93188..9b2d5469 100644 --- a/README.md +++ b/README.md @@ -60,14 +60,16 @@ In a new terminal window ``` bench update ``` +### Testing +#### Running Cypress tests +To set up local Cypress tests; +```bash +cd apps/check_run +yarn +``` +Additional steps may be required on WSL, use Nicky's guide: +https://nickymeuleman.netlify.app/blog/gui-on-wsl2-cypress -### Printer Server setup -``` -sudo apt-get install gcc cups python3-dev libcups2-dev -y -bench pip install pycups -sudo usermod -a -G lpadmin {username} # the "frappe" user in most installations -``` -Go to `{server URL or localhost}:631` to access the CUPS web interface -Configuration on a remote server will take extra steps to secure: -https://askubuntu.com/questions/23936/how-do-you-administer-cups-remotely-using-the-web-interface - +```bash +yarn run cypress open +``` \ No newline at end of file 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 dddb5935..4e662759 100644 --- a/check_run/check_run/doctype/check_run/check_run.js +++ b/check_run/check_run/doctype/check_run/check_run.js @@ -2,6 +2,7 @@ // For license information, please see license.txt frappe.ui.form.on("Check Run", { validate: frm => { + validate_mode_of_payment_mandatory(frm) if(frm.check_run_state.party_filter.length > 0) { frm.check_run_state.party_filter = "" frm.check_run_state.show_party_filter = false @@ -45,6 +46,10 @@ frappe.ui.form.on("Check Run", { onload_post_render: frm => { frm.page.wrapper.find('.layout-side-section').hide() permit_first_user(frm) + frappe.xcall('check_run.check_run.doctype.check_run.check_run.get_balance', { doc: frm.doc }) + .then(r => { + frm.set_value('beg_balance', r) + }) }, end_date: frm => { get_entries(frm) @@ -117,11 +122,6 @@ function get_defaults(frm){ if(!frm.is_new()){ return } frm.set_value('start_date', moment().startOf('week').format()) frm.set_value('end_date', moment().endOf('week').format()) - frappe.db.get_value('Company', frm.doc.company, ['default_bank_account', 'default_payable_account']) - .then(r => { - frm.set_value('bank_account', r.message.default_bank_account) - frm.set_value('pay_to_account', r.message.default_payable_account) - }) } function get_last_check_number(frm){ @@ -198,7 +198,7 @@ function reprint_checks(frm){ { fieldname: 'reprint_check_number', fieldtype: 'Data', - label: "New Intial Check Number", + label: "New Initial Check Number", } ], minimizable: false, @@ -212,3 +212,26 @@ function reprint_checks(frm){ }) d.show() } + + +function validate_mode_of_payment_mandatory(frm){ + let mode_of_payment_required = [] + for(const index in frm.check_run_state.transactions){ + let row = frm.check_run_state.transactions[index] + if (row.pay && row.mode_of_payment.length < 2){ + mode_of_payment_required.push({ row: index + 1, party: row.party, ref_name: row.ref_number || row.name }) + } + } + if (mode_of_payment_required.length == 0){ return } + let message = '' + for (const index in mode_of_payment_required) { + let row = mode_of_payment_required[index] + message += `
  • Row ${row.row}: ${row.party} - ${row.ref_name}
  • ` + } + frappe.msgprint({ + message: `

    `, + indicator: 'red', + title: __('Mode of Payment Required'), + raise_exception: true, + }) +} \ No newline at end of file diff --git a/check_run/check_run/doctype/check_run/check_run.json b/check_run/check_run/doctype/check_run/check_run.json index b953152e..85a92149 100644 --- a/check_run/check_run/doctype/check_run/check_run.json +++ b/check_run/check_run/doctype/check_run/check_run.json @@ -81,6 +81,8 @@ }, { "allow_in_quick_entry": 1, + "fetch_from": "company.default_bank_account", + "fetch_if_empty": 1, "fieldname": "bank_account", "fieldtype": "Link", "label": "Paid From (Bank Account)", @@ -89,6 +91,7 @@ "reqd": 1 }, { + "default": "company.default_payable_account", "fieldname": "pay_to_account", "fieldtype": "Link", "label": "Accounts Payable", @@ -155,7 +158,7 @@ ], "is_submittable": 1, "links": [], - "modified": "2022-07-08 10:10:39.971682", + "modified": "2022-07-10 16:16:03.289288", "modified_by": "Administrator", "module": "Check Run", "name": "Check Run", 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 11789053..780cdc08 100644 --- a/check_run/check_run/doctype/check_run/check_run.py +++ b/check_run/check_run/doctype/check_run/check_run.py @@ -24,6 +24,7 @@ def validate(self): gl_account = frappe.get_value('Bank Account', self.bank_account, 'account') if not gl_account: frappe.throw(frappe._("This Bank Account is not associated with a General Ledger Account.")) + self.beg_balance = get_balance_on(gl_account, self.check_run_date) if self.flags.in_insert: if self.initial_check_number is None: self.get_last_check_number() @@ -118,13 +119,12 @@ def create_payment_entries(self, transactions): pe = frappe.new_doc("Payment Entry") pe.payment_type = "Pay" pe.posting_date = nowdate() - pe.cost_center = frappe.get_value('Account', self.pay_to_account, 'cost_center') - department = self.get_dimensions_from_references(group, 'department') - if department != 'None' and department: - pe.department = department project = self.get_dimensions_from_references(group, 'project') if project != 'None' and project: pe.project = project + cost_center = self.get_dimensions_from_references(group, 'cost_center') + if cost_center != 'None' and project: + pe.cost_center = cost_center pe.mode_of_payment = group[0].mode_of_payment pe.company = self.company pe.paid_from = gl_account @@ -234,11 +234,12 @@ def print_checks(docname, reprint_check_number=None): @frappe.whitelist() -def check_for_draft_check_run(company, bank_account): +def check_for_draft_check_run(company, bank_account, payable_account): existing = frappe.get_value( 'Check Run', { 'company': company, 'bank_account': bank_account, + 'pay_to_account': payable_account, 'status': ['in', ['Draft', 'Submitted']], 'initial_check_number': ['!=', 0] } @@ -248,6 +249,7 @@ def check_for_draft_check_run(company, bank_account): cr = frappe.new_doc('Check Run') cr.company = company cr.bank_account = bank_account + cr.pay_to_account = payable_account cr.save() return cr.name @@ -269,6 +271,7 @@ def get_entries(doc): ( SELECT 'Purchase Invoice' as doctype, + 'Supplier' AS party_type, `tabPurchase Invoice`.name, `tabPurchase Invoice`.bill_no AS ref_number, `tabPurchase Invoice`.supplier_name AS party, @@ -289,6 +292,7 @@ def get_entries(doc): ( SELECT 'Expense Claim' as doctype, + 'Employee' AS party_type, `tabExpense Claim`.name, `tabExpense Claim`.name AS ref_number, `tabExpense Claim`.employee_name AS party, @@ -311,6 +315,7 @@ def get_entries(doc): `tabJournal Entry`.name AS ref_number, `tabJournal Entry Account`.party AS party, `tabJournal Entry Account`.party AS party_ref, + `tabJournal Entry Account`.party_type, `tabJournal Entry Account`.credit_in_account_currency AS amount, `tabJournal Entry`.due_date AS due_date, `tabJournal Entry`.posting_date, @@ -338,7 +343,6 @@ def get_entries(doc): @frappe.whitelist() def get_balance(doc): doc = frappe._dict(json.loads(doc)) if isinstance(doc, str) else doc - print(doc) if not doc.bank_account or not doc.check_run_date: return gl_account = frappe.get_value('Bank Account', doc.bank_account, 'account') diff --git a/check_run/check_run/doctype/check_run/test_check_run.py b/check_run/check_run/doctype/check_run/test_check_run.py index d1116a51..0249e1b8 100644 --- a/check_run/check_run/doctype/check_run/test_check_run.py +++ b/check_run/check_run/doctype/check_run/test_check_run.py @@ -5,9 +5,7 @@ import unittest -def before_tests(): - print('before tests') - - class TestCheckRun(unittest.TestCase): pass + + diff --git a/check_run/public/build.json b/check_run/public/build.json index f5cab58b..3bff0827 100644 --- a/check_run/public/build.json +++ b/check_run/public/build.json @@ -1,6 +1,6 @@ { "js/check_run.min.js": [ "public/js/check_run/check_run.js", - "public/js/custom/check_run_quick_entry.js" + "public/js/check_run/check_run_quick_entry.js" ] } \ No newline at end of file diff --git a/check_run/public/js/check_run/ADropdown.vue b/check_run/public/js/check_run/ADropdown.vue index b7c61005..581f61cc 100644 --- a/check_run/public/js/check_run/ADropdown.vue +++ b/check_run/public/js/check_run/ADropdown.vue @@ -1,6 +1,7 @@