mirror of
https://github.com/frappe/erpnext.git
synced 2026-02-18 17:15:04 +00:00
Merge branch 'develop' into payment_entry_validations_and_trigger_develop
This commit is contained in:
@@ -154,7 +154,8 @@
|
||||
"before": true,
|
||||
"beforeEach": true,
|
||||
"onScan": true,
|
||||
"html2canvas": true,
|
||||
"extend_cscript": true,
|
||||
"localforage": true,
|
||||
"localforage": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,3 +13,6 @@
|
||||
|
||||
# This commit just changes spaces to tabs for indentation in some files
|
||||
5f473611bd6ed57703716244a054d3fb5ba9cd23
|
||||
|
||||
# Whitespace fix throughout codebase
|
||||
4551d7d6029b6f587f6c99d4f8df5519241c6a86
|
||||
|
||||
12
.github/helper/documentation.py
vendored
12
.github/helper/documentation.py
vendored
@@ -32,11 +32,15 @@ if __name__ == "__main__":
|
||||
|
||||
if response.ok:
|
||||
payload = response.json()
|
||||
title = payload.get("title", "").lower()
|
||||
head_sha = payload.get("head", {}).get("sha")
|
||||
body = payload.get("body", "").lower()
|
||||
title = (payload.get("title") or "").lower().strip()
|
||||
head_sha = (payload.get("head") or {}).get("sha")
|
||||
body = (payload.get("body") or "").lower()
|
||||
|
||||
if title.startswith("feat") and head_sha and "no-docs" not in body:
|
||||
if (title.startswith("feat")
|
||||
and head_sha
|
||||
and "no-docs" not in body
|
||||
and "backport" not in body
|
||||
):
|
||||
if docs_link_exists(body):
|
||||
print("Documentation Link Found. You're Awesome! 🎉")
|
||||
|
||||
|
||||
8
.github/workflows/patch.yml
vendored
8
.github/workflows/patch.yml
vendored
@@ -1,6 +1,12 @@
|
||||
name: Patch
|
||||
|
||||
on: [pull_request, workflow_dispatch]
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.js'
|
||||
- '**.md'
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
||||
6
.github/workflows/server-tests.yml
vendored
6
.github/workflows/server-tests.yml
vendored
@@ -2,9 +2,15 @@ name: Server
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.js'
|
||||
- '**.md'
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ develop ]
|
||||
paths-ignore:
|
||||
- '**.js'
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
||||
4
.github/workflows/ui-tests.yml
vendored
4
.github/workflows/ui-tests.yml
vendored
@@ -2,6 +2,8 @@ name: UI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -102,7 +104,7 @@ jobs:
|
||||
- name: UI Tests
|
||||
run: cd ~/frappe-bench/ && bench --site test_site run-ui-tests erpnext --headless
|
||||
env:
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
CYPRESS_RECORD_KEY: 60a8e3bf-08f5-45b1-9269-2b207d7d30cd
|
||||
|
||||
- name: Show bench console if tests failed
|
||||
if: ${{ failure() }}
|
||||
|
||||
113
cypress/integration/test_organizational_chart_desktop.js
Normal file
113
cypress/integration/test_organizational_chart_desktop.js
Normal file
@@ -0,0 +1,113 @@
|
||||
context('Organizational Chart', () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.visit('/app/website');
|
||||
cy.awesomebar('Organizational Chart');
|
||||
cy.wait(500);
|
||||
cy.url().should('include', '/organizational-chart');
|
||||
|
||||
cy.window().its('frappe.csrf_token').then(csrf_token => {
|
||||
return cy.request({
|
||||
url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'X-Frappe-CSRF-Token': csrf_token
|
||||
},
|
||||
timeout: 60000
|
||||
}).then(res => {
|
||||
expect(res.status).eq(200);
|
||||
cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
|
||||
cy.get('@input')
|
||||
.clear({ force: true })
|
||||
.type('Test Org Chart{enter}', { force: true })
|
||||
.blur({ force: true });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('renders root nodes and loads children for the first expandable node', () => {
|
||||
// check rendered root nodes and the node name, title, connections
|
||||
cy.get('.hierarchy').find('.root-level ul.node-children').children()
|
||||
.should('have.length', 2)
|
||||
.first()
|
||||
.as('first-child');
|
||||
|
||||
cy.get('@first-child').get('.node-name').contains('Test Employee 1');
|
||||
cy.get('@first-child').get('.node-info').find('.node-title').contains('CEO');
|
||||
cy.get('@first-child').get('.node-info').find('.node-connections').contains('· 2 Connections');
|
||||
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
// children of 1st root visible
|
||||
cy.get(`div[data-parent="${employee_records.message[0]}"]`).as('child-node');
|
||||
cy.get('@child-node')
|
||||
.should('have.length', 1)
|
||||
.should('be.visible');
|
||||
cy.get('@child-node').get('.node-name').contains('Test Employee 3');
|
||||
|
||||
// connectors between first root node and immediate child
|
||||
cy.get(`path[data-parent="${employee_records.message[0]}"]`)
|
||||
.should('be.visible')
|
||||
.invoke('attr', 'data-child')
|
||||
.should('equal', employee_records.message[2]);
|
||||
});
|
||||
});
|
||||
|
||||
it('hides active nodes children and connectors on expanding sibling node', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
// click sibling
|
||||
cy.get(`#${employee_records.message[1]}`)
|
||||
.click()
|
||||
.should('have.class', 'active');
|
||||
|
||||
// child nodes and connectors hidden
|
||||
cy.get(`[data-parent="${employee_records.message[0]}"]`).should('not.be.visible');
|
||||
cy.get(`path[data-parent="${employee_records.message[0]}"]`).should('not.be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('collapses previous level nodes and refreshes connectors on expanding child node', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
// click child node
|
||||
cy.get(`#${employee_records.message[3]}`)
|
||||
.click()
|
||||
.should('have.class', 'active');
|
||||
|
||||
// previous level nodes: parent should be on active-path; other nodes should be collapsed
|
||||
cy.get(`#${employee_records.message[0]}`).should('have.class', 'collapsed');
|
||||
cy.get(`#${employee_records.message[1]}`).should('have.class', 'active-path');
|
||||
|
||||
// previous level connectors refreshed
|
||||
cy.get(`path[data-parent="${employee_records.message[1]}"]`)
|
||||
.should('have.class', 'collapsed-connector');
|
||||
|
||||
// child node's children and connectors rendered
|
||||
cy.get(`[data-parent="${employee_records.message[3]}"]`).should('be.visible');
|
||||
cy.get(`path[data-parent="${employee_records.message[3]}"]`).should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('expands previous level nodes', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
cy.get(`#${employee_records.message[0]}`)
|
||||
.click()
|
||||
.should('have.class', 'active');
|
||||
|
||||
cy.get(`[data-parent="${employee_records.message[0]}"]`)
|
||||
.should('be.visible');
|
||||
|
||||
cy.get('ul.hierarchy').children().should('have.length', 2);
|
||||
cy.get(`#connectors`).children().should('have.length', 1);
|
||||
});
|
||||
});
|
||||
|
||||
it('edit node navigates to employee master', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
cy.get(`#${employee_records.message[0]}`).find('.btn-edit-node')
|
||||
.click();
|
||||
|
||||
cy.url().should('include', `/employee/${employee_records.message[0]}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
190
cypress/integration/test_organizational_chart_mobile.js
Normal file
190
cypress/integration/test_organizational_chart_mobile.js
Normal file
@@ -0,0 +1,190 @@
|
||||
context('Organizational Chart Mobile', () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.viewport(375, 667);
|
||||
cy.visit('/app/website');
|
||||
cy.awesomebar('Organizational Chart');
|
||||
|
||||
cy.window().its('frappe.csrf_token').then(csrf_token => {
|
||||
return cy.request({
|
||||
url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'X-Frappe-CSRF-Token': csrf_token
|
||||
},
|
||||
timeout: 60000
|
||||
}).then(res => {
|
||||
expect(res.status).eq(200);
|
||||
cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
|
||||
cy.get('@input')
|
||||
.clear({ force: true })
|
||||
.type('Test Org Chart{enter}', { force: true })
|
||||
.blur({ force: true });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('renders root nodes', () => {
|
||||
// check rendered root nodes and the node name, title, connections
|
||||
cy.get('.hierarchy-mobile').find('.root-level').children()
|
||||
.should('have.length', 2)
|
||||
.first()
|
||||
.as('first-child');
|
||||
|
||||
cy.get('@first-child').get('.node-name').contains('Test Employee 1');
|
||||
cy.get('@first-child').get('.node-info').find('.node-title').contains('CEO');
|
||||
cy.get('@first-child').get('.node-info').find('.node-connections').contains('· 2');
|
||||
});
|
||||
|
||||
it('expands root node', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
cy.get(`#${employee_records.message[1]}`)
|
||||
.click()
|
||||
.should('have.class', 'active');
|
||||
|
||||
// other root node removed
|
||||
cy.get(`#${employee_records.message[0]}`).should('not.exist');
|
||||
|
||||
// children of active root node
|
||||
cy.get('.hierarchy-mobile').find('.level').first().find('ul.node-children').children()
|
||||
.should('have.length', 2);
|
||||
|
||||
cy.get(`div[data-parent="${employee_records.message[1]}"]`).first().as('child-node');
|
||||
cy.get('@child-node').should('be.visible');
|
||||
|
||||
cy.get('@child-node')
|
||||
.get('.node-name')
|
||||
.contains('Test Employee 4');
|
||||
|
||||
// connectors between root node and immediate children
|
||||
cy.get(`path[data-parent="${employee_records.message[1]}"]`).as('connectors');
|
||||
cy.get('@connectors')
|
||||
.should('have.length', 2)
|
||||
.should('be.visible');
|
||||
|
||||
cy.get('@connectors')
|
||||
.first()
|
||||
.invoke('attr', 'data-child')
|
||||
.should('eq', employee_records.message[3]);
|
||||
});
|
||||
});
|
||||
|
||||
it('expands child node', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
cy.get(`#${employee_records.message[3]}`)
|
||||
.click()
|
||||
.should('have.class', 'active')
|
||||
.as('expanded_node');
|
||||
|
||||
// 2 levels on screen; 1 on active path; 1 collapsed
|
||||
cy.get('.hierarchy-mobile').children().should('have.length', 2);
|
||||
cy.get(`#${employee_records.message[1]}`).should('have.class', 'active-path');
|
||||
|
||||
// children of expanded node visible
|
||||
cy.get('@expanded_node')
|
||||
.next()
|
||||
.should('have.class', 'node-children')
|
||||
.as('node-children');
|
||||
|
||||
cy.get('@node-children').children().should('have.length', 1);
|
||||
cy.get('@node-children')
|
||||
.first()
|
||||
.get('.node-card')
|
||||
.should('have.class', 'active-child')
|
||||
.contains('Test Employee 7');
|
||||
|
||||
// orphan connectors removed
|
||||
cy.get(`#connectors`).children().should('have.length', 2);
|
||||
});
|
||||
});
|
||||
|
||||
it('renders sibling group', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
// sibling group visible for parent
|
||||
cy.get(`#${employee_records.message[1]}`)
|
||||
.next()
|
||||
.as('sibling_group');
|
||||
|
||||
cy.get('@sibling_group')
|
||||
.should('have.attr', 'data-parent', 'undefined')
|
||||
.should('have.class', 'node-group')
|
||||
.and('have.class', 'collapsed');
|
||||
|
||||
cy.get('@sibling_group').get('.avatar-group').children().as('siblings');
|
||||
cy.get('@siblings').should('have.length', 1);
|
||||
cy.get('@siblings')
|
||||
.first()
|
||||
.should('have.attr', 'title', 'Test Employee 1');
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
it('expands previous level nodes', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
cy.get(`#${employee_records.message[6]}`)
|
||||
.click()
|
||||
.should('have.class', 'active');
|
||||
|
||||
// clicking on previous level node should remove all the nodes ahead
|
||||
// and expand that node
|
||||
cy.get(`#${employee_records.message[3]}`).click();
|
||||
cy.get(`#${employee_records.message[3]}`)
|
||||
.should('have.class', 'active')
|
||||
.should('not.have.class', 'active-path');
|
||||
|
||||
cy.get(`#${employee_records.message[6]}`).should('have.class', 'active-child');
|
||||
cy.get('.hierarchy-mobile').children().should('have.length', 2);
|
||||
cy.get(`#connectors`).children().should('have.length', 2);
|
||||
});
|
||||
});
|
||||
|
||||
it('expands sibling group', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
// sibling group visible for parent
|
||||
cy.get(`#${employee_records.message[6]}`).click();
|
||||
|
||||
cy.get(`#${employee_records.message[3]}`)
|
||||
.next()
|
||||
.click();
|
||||
|
||||
// siblings of parent should be visible
|
||||
cy.get('.hierarchy-mobile').prev().as('sibling_group');
|
||||
cy.get('@sibling_group')
|
||||
.should('exist')
|
||||
.should('have.class', 'sibling-group')
|
||||
.should('not.have.class', 'collapsed');
|
||||
|
||||
cy.get(`#${employee_records.message[1]}`)
|
||||
.should('be.visible')
|
||||
.should('have.class', 'active');
|
||||
|
||||
cy.get(`[data-parent="${employee_records.message[1]}"]`)
|
||||
.should('be.visible')
|
||||
.should('have.length', 2)
|
||||
.should('have.class', 'active-child');
|
||||
});
|
||||
});
|
||||
|
||||
it('goes to the respective level after clicking on non-collapsed sibling group', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(() => {
|
||||
// click on non-collapsed sibling group
|
||||
cy.get('.hierarchy-mobile')
|
||||
.prev()
|
||||
.click();
|
||||
|
||||
// should take you to that level
|
||||
cy.get('.hierarchy-mobile').find('li.level .node-card').should('have.length', 2);
|
||||
});
|
||||
});
|
||||
|
||||
it('edit node navigates to employee master', () => {
|
||||
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
|
||||
cy.get(`#${employee_records.message[0]}`).find('.btn-edit-node')
|
||||
.click();
|
||||
|
||||
cy.url().should('include', `/employee/${employee_records.message[0]}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -6,4 +6,4 @@
|
||||
"scss/at-rule-no-unknown": true,
|
||||
"no-descending-specificity": null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import frappe
|
||||
from erpnext.hooks import regional_overrides
|
||||
from frappe.utils import getdate
|
||||
|
||||
__version__ = '13.8.0'
|
||||
__version__ = '13.9.0'
|
||||
|
||||
def get_default_company(user=None):
|
||||
'''Get default company for user'''
|
||||
|
||||
@@ -19,4 +19,4 @@ frappe.dashboards.chart_sources["Account Balance Timeline"] = {
|
||||
reqd: 1
|
||||
},
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
@@ -450,5 +450,3 @@ def get_deferred_booking_accounts(doctype, voucher_detail_no, dr_or_cr):
|
||||
return debit_account
|
||||
else:
|
||||
return credit_account
|
||||
|
||||
|
||||
|
||||
@@ -60,4 +60,4 @@ frappe.ui.form.on('Accounting Dimension Detail', {
|
||||
let row = locals[cdt][cdn];
|
||||
row.reference_document = frm.doc.document_type;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -113,5 +113,3 @@ def disable_dimension():
|
||||
dimension2 = frappe.get_doc("Accounting Dimension", "Location")
|
||||
dimension2.disabled = 1
|
||||
dimension2.save()
|
||||
|
||||
|
||||
|
||||
@@ -79,4 +79,4 @@ frappe.ui.form.on('Allowed Dimension', {
|
||||
row.accounting_dimension = frm.doc.accounting_dimension;
|
||||
frm.refresh_field("dimensions");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -56,4 +56,4 @@ class AccountingPeriod(Document):
|
||||
self.append('closed_documents', {
|
||||
"document_type": doctype_for_closing.document_type,
|
||||
"closed": doctype_for_closing.closed
|
||||
})
|
||||
})
|
||||
|
||||
@@ -48,4 +48,4 @@ frappe.tour['Accounts Settings'] = [
|
||||
title: "Unlink Advance Payment on Cancellation of Order",
|
||||
description: __("Similar to the previous option, this unlinks any advance payments made against Purchase/Sales Orders.")
|
||||
}
|
||||
];
|
||||
];
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"book_asset_depreciation_entry_automatically",
|
||||
"unlink_advance_payment_on_cancelation_of_order",
|
||||
"post_change_gl_entries",
|
||||
"enable_discount_accounting",
|
||||
"tax_settings_section",
|
||||
"determine_address_tax_category_from",
|
||||
"column_break_19",
|
||||
@@ -260,6 +261,13 @@
|
||||
"fieldname": "post_change_gl_entries",
|
||||
"fieldtype": "Check",
|
||||
"label": "Create Ledger Entries for Change Amount"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "If enabled, additional ledger entries will be made for discounts in a separate Discount Account",
|
||||
"fieldname": "enable_discount_accounting",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enable Discount Accounting"
|
||||
}
|
||||
],
|
||||
"icon": "icon-cog",
|
||||
@@ -267,7 +275,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2021-08-09 13:08:01.335416",
|
||||
"modified": "2021-08-09 13:08:04.335416",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts Settings",
|
||||
|
||||
@@ -21,6 +21,7 @@ class AccountsSettings(Document):
|
||||
|
||||
self.validate_stale_days()
|
||||
self.enable_payment_schedule_in_print()
|
||||
self.toggle_discount_accounting_fields()
|
||||
|
||||
def validate_stale_days(self):
|
||||
if not self.allow_stale and cint(self.stale_days) <= 0:
|
||||
@@ -33,3 +34,22 @@ class AccountsSettings(Document):
|
||||
for doctype in ("Sales Order", "Sales Invoice", "Purchase Order", "Purchase Invoice"):
|
||||
make_property_setter(doctype, "due_date", "print_hide", show_in_print, "Check", validate_fields_for_doctype=False)
|
||||
make_property_setter(doctype, "payment_schedule", "print_hide", 0 if show_in_print else 1, "Check", validate_fields_for_doctype=False)
|
||||
|
||||
def toggle_discount_accounting_fields(self):
|
||||
enable_discount_accounting = cint(self.enable_discount_accounting)
|
||||
|
||||
for doctype in ["Sales Invoice Item", "Purchase Invoice Item"]:
|
||||
make_property_setter(doctype, "discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
|
||||
if enable_discount_accounting:
|
||||
make_property_setter(doctype, "discount_account", "mandatory_depends_on", "eval: doc.discount_amount", "Code", validate_fields_for_doctype=False)
|
||||
else:
|
||||
make_property_setter(doctype, "discount_account", "mandatory_depends_on", "", "Code", validate_fields_for_doctype=False)
|
||||
|
||||
for doctype in ["Sales Invoice", "Purchase Invoice"]:
|
||||
make_property_setter(doctype, "additional_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
|
||||
if enable_discount_accounting:
|
||||
make_property_setter(doctype, "additional_discount_account", "mandatory_depends_on", "eval: doc.discount_amount", "Code", validate_fields_for_doctype=False)
|
||||
else:
|
||||
make_property_setter(doctype, "additional_discount_account", "mandatory_depends_on", "", "Code", validate_fields_for_doctype=False)
|
||||
|
||||
make_property_setter("Item", "default_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
|
||||
|
||||
@@ -5,4 +5,4 @@ frappe.ui.form.on('Accounts Settings', {
|
||||
frm.set_df_property("frozen_accounts_modifier", "label", "Role Allowed to Close Books & Make Changes to Closed Periods");
|
||||
frm.set_df_property("credit_controller", "label", "Credit Manager");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -120,4 +120,4 @@ erpnext.integrations.refreshPlaidLink = class refreshPlaidLink {
|
||||
plaid_success(token, response) {
|
||||
frappe.show_alert({ message: __('Plaid Link Updated'), indicator: 'green' });
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -13,4 +13,4 @@ class Bank(Document):
|
||||
load_address_and_contact(self)
|
||||
|
||||
def on_trash(self):
|
||||
delete_contact_and_address('Bank', self.name)
|
||||
delete_contact_and_address('Bank', self.name)
|
||||
|
||||
@@ -26,4 +26,4 @@ def get_data():
|
||||
'items': ['Journal Entry']
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ frappe.ui.form.on("Bank Clearance", {
|
||||
|
||||
onload: function(frm) {
|
||||
|
||||
let default_bank_account = frappe.defaults.get_user_default("Company")?
|
||||
let default_bank_account = frappe.defaults.get_user_default("Company")?
|
||||
locals[":Company"][frappe.defaults.get_user_default("Company")]["default_bank_account"]: "";
|
||||
frm.set_value("account", default_bank_account);
|
||||
|
||||
|
||||
@@ -6,4 +6,4 @@ import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class BankClearanceDetail(Document):
|
||||
pass
|
||||
pass
|
||||
|
||||
@@ -25,6 +25,6 @@ class BankGuarantee(Document):
|
||||
def get_vouchar_detials(column_list, doctype, docname):
|
||||
column_list = json.loads(column_list)
|
||||
for col in column_list:
|
||||
sanitize_searchfield(col)
|
||||
sanitize_searchfield(col)
|
||||
return frappe.db.sql(''' select {columns} from `tab{doctype}` where name=%s'''
|
||||
.format(columns=", ".join(column_list), doctype=doctype), docname, as_dict=1)[0]
|
||||
|
||||
@@ -105,4 +105,3 @@ def unclear_reference_payment(doctype, docname):
|
||||
frappe.db.set_value(doc.payment_document, doc.payment_entry, "clearance_date", None)
|
||||
|
||||
return doc.payment_entry
|
||||
|
||||
|
||||
@@ -10,4 +10,4 @@ frappe.listview_settings['Bank Transaction'] = {
|
||||
return [__("Reconciled"), "green", "unallocated_amount,=,0"];
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -77,4 +77,4 @@ def get_bank_mapping(bank_account):
|
||||
|
||||
mapping = {row.file_field:row.bank_transaction_field for row in bank.bank_transaction_mapping}
|
||||
|
||||
return mapping
|
||||
return mapping
|
||||
|
||||
@@ -6,4 +6,4 @@ import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class CFormInvoiceDetail(Document):
|
||||
pass
|
||||
pass
|
||||
|
||||
31
erpnext/accounts/doctype/campaign_item/campaign_item.json
Normal file
31
erpnext/accounts/doctype/campaign_item/campaign_item.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2021-05-06 16:18:25.410476",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"campaign"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "campaign",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Campaign",
|
||||
"options": "Campaign"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-05-07 10:43:49.717633",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Campaign Item",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
8
erpnext/accounts/doctype/campaign_item/campaign_item.py
Normal file
8
erpnext/accounts/doctype/campaign_item/campaign_item.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class CampaignItem(Document):
|
||||
pass
|
||||
@@ -18,5 +18,3 @@ class CashFlowMapping(Document):
|
||||
frappe._('You can only select a maximum of one option from the list of check boxes.'),
|
||||
title='Error'
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -33,4 +33,4 @@ class CashierClosing(Document):
|
||||
|
||||
def validate_time(self):
|
||||
if self.from_time >= self.time:
|
||||
frappe.throw(_("From Time Should Be Less Than To Time"))
|
||||
frappe.throw(_("From Time Should Be Less Than To Time"))
|
||||
|
||||
@@ -10,10 +10,10 @@ frappe.ui.form.on('Cheque Print Template', {
|
||||
function() {
|
||||
erpnext.cheque_print.view_cheque_print(frm);
|
||||
}).addClass("btn-primary");
|
||||
|
||||
|
||||
$(frm.fields_dict.cheque_print_preview.wrapper).empty()
|
||||
|
||||
|
||||
|
||||
|
||||
var template = '<div style="position: relative; overflow-x: scroll;">\
|
||||
<div id="cheque_preview" style="width: {{ cheque_width }}cm; \
|
||||
height: {{ cheque_height }}cm;\
|
||||
@@ -47,9 +47,9 @@ frappe.ui.form.on('Cheque Print Template', {
|
||||
position: absolute;"> Signatory Name </span>\
|
||||
</div>\
|
||||
</div>';
|
||||
|
||||
|
||||
$(frappe.render(template, frm.doc)).appendTo(frm.fields_dict.cheque_print_preview.wrapper)
|
||||
|
||||
|
||||
if (frm.doc.scanned_cheque) {
|
||||
$(frm.fields_dict.cheque_print_preview.wrapper).find("#cheque_preview").css('background-image', 'url(' + frm.doc.scanned_cheque + ')');
|
||||
}
|
||||
|
||||
@@ -129,4 +129,4 @@ def get_name_with_number(new_account, account_number):
|
||||
|
||||
def check_if_distributed_cost_center_enabled(cost_center_list):
|
||||
value_list = frappe.get_list("Cost Center", {"name": ["in", cost_center_list]}, "enable_distributed_cost_center", as_list=1)
|
||||
return next((True for x in value_list if x[0]), False)
|
||||
return next((True for x in value_list if x[0]), False)
|
||||
|
||||
@@ -12,4 +12,4 @@ def get_data():
|
||||
'items': ['Budget Variance Report', 'General Ledger']
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,4 +51,4 @@ frappe.treeview_settings["Cost Center"] = {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,3 @@ def create_cost_center(**args):
|
||||
cc.is_group = args.is_group or 0
|
||||
cc.parent_cost_center = args.parent_cost_center or "_Test Company - _TC"
|
||||
cc.insert()
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ class CouponCode(Document):
|
||||
self.coupon_code =''.join(i for i in self.coupon_name if not i.isdigit())[0:8].upper()
|
||||
elif self.coupon_type == "Gift Card":
|
||||
self.coupon_code = frappe.generate_hash()[:10].upper()
|
||||
|
||||
|
||||
def validate(self):
|
||||
if self.coupon_type == "Gift Card":
|
||||
self.maximum_use = 1
|
||||
|
||||
@@ -57,7 +57,7 @@ def test_create_test_data():
|
||||
})
|
||||
item_price.insert()
|
||||
# create test item pricing rule
|
||||
if not frappe.db.exists("Pricing Rule","_Test Pricing Rule for _Test Item"):
|
||||
if not frappe.db.exists("Pricing Rule", {"title": "_Test Pricing Rule for _Test Item"}):
|
||||
item_pricing_rule = frappe.get_doc({
|
||||
"doctype": "Pricing Rule",
|
||||
"title": "_Test Pricing Rule for _Test Item",
|
||||
@@ -86,14 +86,15 @@ def test_create_test_data():
|
||||
sales_partner.insert()
|
||||
# create test item coupon code
|
||||
if not frappe.db.exists("Coupon Code", "SAVE30"):
|
||||
pricing_rule = frappe.db.get_value("Pricing Rule", {"title": "_Test Pricing Rule for _Test Item"}, ['name'])
|
||||
coupon_code = frappe.get_doc({
|
||||
"doctype": "Coupon Code",
|
||||
"coupon_name":"SAVE30",
|
||||
"coupon_code":"SAVE30",
|
||||
"pricing_rule": "_Test Pricing Rule for _Test Item",
|
||||
"valid_from": "2014-01-01",
|
||||
"maximum_use":1,
|
||||
"used":0
|
||||
"doctype": "Coupon Code",
|
||||
"coupon_name":"SAVE30",
|
||||
"coupon_code":"SAVE30",
|
||||
"pricing_rule": pricing_rule,
|
||||
"valid_from": "2014-01-01",
|
||||
"maximum_use":1,
|
||||
"used":0
|
||||
})
|
||||
coupon_code.insert()
|
||||
|
||||
@@ -102,7 +103,7 @@ class TestCouponCode(unittest.TestCase):
|
||||
test_create_test_data()
|
||||
|
||||
def tearDown(self):
|
||||
frappe.set_user("Administrator")
|
||||
frappe.set_user("Administrator")
|
||||
|
||||
def test_sales_order_with_coupon_code(self):
|
||||
frappe.db.set_value("Coupon Code", "SAVE30", "used", 0)
|
||||
@@ -123,6 +124,3 @@ class TestCouponCode(unittest.TestCase):
|
||||
|
||||
so.submit()
|
||||
self.assertEqual(frappe.db.get_value("Coupon Code", "SAVE30", "used"), 1)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2021-05-06 16:12:42.558878",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"customer_group"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "customer_group",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Customer Group",
|
||||
"options": "Customer Group"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-05-07 10:39:21.563506",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Customer Group Item",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class CustomerGroupItem(Document):
|
||||
pass
|
||||
31
erpnext/accounts/doctype/customer_item/customer_item.json
Normal file
31
erpnext/accounts/doctype/customer_item/customer_item.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2021-05-05 14:04:54.266353",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"customer"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "customer",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Customer ",
|
||||
"options": "Customer"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-05-06 10:02:32.967841",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Customer Item",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
8
erpnext/accounts/doctype/customer_item/customer_item.py
Normal file
8
erpnext/accounts/doctype/customer_item/customer_item.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class CustomerItem(Document):
|
||||
pass
|
||||
@@ -7,4 +7,4 @@ from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
class DiscountedInvoice(Document):
|
||||
pass
|
||||
pass
|
||||
|
||||
@@ -14,4 +14,4 @@ def get_data():
|
||||
'items': ['Payment Entry', 'Journal Entry']
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,4 +143,4 @@ def create_dunning_type_with_zero_interest_rate():
|
||||
'closing_text': 'We kindly request that you pay the outstanding amount immediately, and late fees.'
|
||||
}
|
||||
)
|
||||
dunning_type.save()
|
||||
dunning_type.save()
|
||||
|
||||
@@ -31,7 +31,7 @@ frappe.ui.form.on('Exchange Rate Revaluation', {
|
||||
}, __('Create'));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -128,4 +128,4 @@ var get_account_details = function(frm, cdt, cdn) {
|
||||
frm.events.get_total_gain_loss(frm);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
@@ -44,7 +44,7 @@ class ExchangeRateRevaluation(Document):
|
||||
|
||||
if total_amt != total_debit:
|
||||
return True
|
||||
|
||||
|
||||
return False
|
||||
|
||||
@frappe.whitelist()
|
||||
@@ -205,4 +205,4 @@ def get_account_details(account, company, posting_date, party_type=None, party=N
|
||||
"new_balance_in_base_currency": new_balance_in_base_currency
|
||||
}
|
||||
|
||||
return account_details
|
||||
return account_details
|
||||
|
||||
@@ -19,7 +19,7 @@ class TestFinanceBook(unittest.TestCase):
|
||||
finance_book = frappe.get_doc("Finance Book", "_Test Finance Book")
|
||||
|
||||
return finance_book
|
||||
|
||||
|
||||
def test_finance_book(self):
|
||||
finance_book = self.create_finance_book()
|
||||
|
||||
|
||||
@@ -17,4 +17,4 @@ def get_data():
|
||||
'items': ['Payment Entry', 'Journal Entry']
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,4 +18,4 @@ frappe.listview_settings['Invoice Discounting'] = {
|
||||
return [__("Canceled"), "red", "status,=,Canceled"];
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -14,4 +14,4 @@ frappe.ui.form.on("Journal Entry", {
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -100,7 +100,7 @@ class TestJournalEntry(unittest.TestCase):
|
||||
"debit_in_account_currency": 0 if diff > 0 else abs(diff),
|
||||
"credit_in_account_currency": diff if diff > 0 else 0
|
||||
})
|
||||
|
||||
|
||||
jv.append("accounts", {
|
||||
"account": "Stock Adjustment - TCP1",
|
||||
"cost_center": "Main - TCP1",
|
||||
|
||||
@@ -88,4 +88,4 @@ frappe.ui.form.on("Journal Entry Template", {
|
||||
frappe.model.clear_table(frm.doc, "accounts");
|
||||
frm.refresh_field("accounts");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,4 +14,4 @@ frappe.ui.form.on('Mode of Payment', {
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -39,4 +39,3 @@ class ModeofPayment(Document):
|
||||
message = "POS Profile " + frappe.bold(", ".join(pos_profiles)) + " contains \
|
||||
Mode of Payment " + frappe.bold(str(self.name)) + ". Please remove them to disable this mode."
|
||||
frappe.throw(_(message), title="Not Allowed")
|
||||
|
||||
|
||||
@@ -55,4 +55,4 @@ def get_percentage(doc, start_date, period):
|
||||
if d.month in months:
|
||||
percentage += d.percentage_allocation
|
||||
|
||||
return percentage
|
||||
return percentage
|
||||
|
||||
@@ -20,4 +20,4 @@ def get_data():
|
||||
'items': ['Budget']
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,4 +162,4 @@ frappe.ui.form.on('Opening Invoice Creation Tool Item', {
|
||||
invoices_add: (frm) => {
|
||||
frm.trigger('update_invoice_table');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -241,4 +241,3 @@ def get_temporary_opening_account(company=None):
|
||||
frappe.throw(_("Please add a Temporary Opening account in Chart of Accounts"))
|
||||
|
||||
return accounts[0].name
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ class PaymentEntry(AccountsController):
|
||||
for field, value in iteritems(ref_details):
|
||||
if d.exchange_gain_loss:
|
||||
# for cases where gain/loss is booked into invoice
|
||||
# exchange_gain_loss is calculated from invoice & populated
|
||||
# exchange_gain_loss is calculated from invoice & populated
|
||||
# and row.exchange_rate is already set to payment entry's exchange rate
|
||||
# refer -> `update_reference_in_payment_entry()` in utils.py
|
||||
continue
|
||||
@@ -427,7 +427,7 @@ class PaymentEntry(AccountsController):
|
||||
net_total_for_tds = 0
|
||||
if reference.reference_doctype == 'Purchase Order':
|
||||
net_total_for_tds += flt(frappe.db.get_value('Purchase Order', reference.reference_name, 'net_total'))
|
||||
|
||||
|
||||
if net_total_for_tds:
|
||||
net_total = net_total_for_tds
|
||||
|
||||
@@ -548,7 +548,7 @@ class PaymentEntry(AccountsController):
|
||||
if self.payment_type == "Receive" \
|
||||
and self.base_total_allocated_amount < self.base_received_amount + total_deductions \
|
||||
and self.total_allocated_amount < self.paid_amount + (total_deductions / self.source_exchange_rate):
|
||||
self.unallocated_amount = (self.received_amount + total_deductions -
|
||||
self.unallocated_amount = (self.base_received_amount + total_deductions -
|
||||
self.base_total_allocated_amount) / self.source_exchange_rate
|
||||
self.unallocated_amount -= included_taxes
|
||||
elif self.payment_type == "Pay" \
|
||||
@@ -860,7 +860,7 @@ class PaymentEntry(AccountsController):
|
||||
|
||||
if account_details:
|
||||
row.update(account_details)
|
||||
|
||||
|
||||
if not row.get('amount'):
|
||||
# if no difference amount
|
||||
return
|
||||
|
||||
@@ -11,4 +11,4 @@ frappe.listview_settings['Payment Entry'] = {
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -295,6 +295,34 @@ class TestPaymentEntry(unittest.TestCase):
|
||||
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
|
||||
self.assertEqual(outstanding_amount, 80)
|
||||
|
||||
def test_payment_entry_against_si_usd_to_usd_with_deduction_in_base_currency (self):
|
||||
si = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
|
||||
currency="USD", conversion_rate=50, do_not_save=1)
|
||||
|
||||
si.plc_conversion_rate = 50
|
||||
si.save()
|
||||
si.submit()
|
||||
|
||||
pe = get_payment_entry("Sales Invoice", si.name, party_amount=20,
|
||||
bank_account="_Test Bank USD - _TC", bank_amount=900)
|
||||
|
||||
pe.source_exchange_rate = 45.263
|
||||
pe.target_exchange_rate = 45.263
|
||||
pe.reference_no = "1"
|
||||
pe.reference_date = "2016-01-01"
|
||||
|
||||
|
||||
pe.append("deductions", {
|
||||
"account": "_Test Exchange Gain/Loss - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"amount": 94.80
|
||||
})
|
||||
|
||||
pe.save()
|
||||
|
||||
self.assertEqual(flt(pe.difference_amount, 2), 0.0)
|
||||
self.assertEqual(flt(pe.unallocated_amount, 2), 0.0)
|
||||
|
||||
def test_payment_entry_retrieves_last_exchange_rate(self):
|
||||
from erpnext.setup.doctype.currency_exchange.test_currency_exchange import test_records, save_new_records
|
||||
|
||||
|
||||
@@ -57,4 +57,4 @@ QUnit.test("test payment entry", function(assert) {
|
||||
() => frappe.timeout(3),
|
||||
() => done()
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -25,4 +25,4 @@ QUnit.test("test payment entry", function(assert) {
|
||||
() => frappe.timeout(0.3),
|
||||
() => done()
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -64,4 +64,4 @@ QUnit.test("test payment entry", function(assert) {
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,19 +9,19 @@ from frappe.model.document import Document
|
||||
class PaymentGatewayAccount(Document):
|
||||
def autoname(self):
|
||||
self.name = self.payment_gateway + " - " + self.currency
|
||||
|
||||
|
||||
def validate(self):
|
||||
self.currency = frappe.db.get_value("Account", self.payment_account, "account_currency")
|
||||
|
||||
|
||||
self.update_default_payment_gateway()
|
||||
self.set_as_default_if_not_set()
|
||||
|
||||
|
||||
def update_default_payment_gateway(self):
|
||||
if self.is_default:
|
||||
frappe.db.sql("""update `tabPayment Gateway Account` set is_default = 0
|
||||
where is_default = 1 """)
|
||||
|
||||
|
||||
def set_as_default_if_not_set(self):
|
||||
if not frappe.db.get_value("Payment Gateway Account",
|
||||
if not frappe.db.get_value("Payment Gateway Account",
|
||||
{"is_default": 1, "name": ("!=", self.name)}, "name"):
|
||||
self.is_default = 1
|
||||
|
||||
@@ -136,4 +136,4 @@ frappe.ui.form.on('Payment Order', {
|
||||
|
||||
dialog.show();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,4 +9,4 @@ def get_data():
|
||||
'items': ['Payment Entry', 'Journal Entry']
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,4 +46,4 @@ def create_payment_order_against_payment_entry(ref_doc, order_type):
|
||||
doc = make_payment_order(ref_doc.name, payment_order)
|
||||
doc.save()
|
||||
doc.submit()
|
||||
return doc
|
||||
return doc
|
||||
|
||||
@@ -307,4 +307,4 @@ def reconcile_dr_cr_note(dr_cr_notes, company):
|
||||
]
|
||||
})
|
||||
jv.flags.ignore_mandatory = True
|
||||
jv.submit()
|
||||
jv.submit()
|
||||
|
||||
@@ -541,4 +541,4 @@ def make_payment_order(source_name, target_doc=None):
|
||||
}
|
||||
}, target_doc, set_missing_values)
|
||||
|
||||
return doclist
|
||||
return doclist
|
||||
|
||||
@@ -138,4 +138,4 @@ class TestPaymentRequest(unittest.TestCase):
|
||||
|
||||
# Try to make Payment Request more than SO amount, should give validation
|
||||
pr2.grand_total = 900
|
||||
self.assertRaises(frappe.ValidationError, pr2.save)
|
||||
self.assertRaises(frappe.ValidationError, pr2.save)
|
||||
|
||||
@@ -19,4 +19,4 @@ frappe.ui.form.on('Payment Term', {
|
||||
frm.set_df_property("discount", "description", description);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
|
||||
frappe.ui.form.on('Payment Terms Template', {
|
||||
setup: function(frm) {
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -30,4 +30,4 @@ def get_data():
|
||||
'items': ['Customer Group', 'Supplier Group']
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ class PeriodClosingVoucher(AccountsController):
|
||||
|
||||
def make_gl_entries(self):
|
||||
gl_entries = []
|
||||
net_pl_balance = 0
|
||||
net_pl_balance = 0
|
||||
|
||||
pl_accounts = self.get_pl_balances()
|
||||
|
||||
@@ -79,7 +79,7 @@ class PeriodClosingVoucher(AccountsController):
|
||||
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
make_gl_entries(gl_entries)
|
||||
|
||||
|
||||
def get_pnl_gl_entry(self, net_pl_balance):
|
||||
cost_center = frappe.db.get_value("Company", self.company, "cost_center")
|
||||
gl_entry = self.get_gl_dict({
|
||||
|
||||
@@ -139,7 +139,7 @@ def create_company():
|
||||
'company_name': "Test PCV Company",
|
||||
'country': 'United States',
|
||||
'default_currency': 'USD'
|
||||
})
|
||||
})
|
||||
company.insert(ignore_if_duplicate = True)
|
||||
return company.name
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ frappe.ui.form.on('POS Closing Entry', {
|
||||
frm.set_query("pos_opening_entry", function(doc) {
|
||||
return { filters: { 'status': 'Open', 'docstatus': 1 } };
|
||||
});
|
||||
|
||||
|
||||
if (frm.doc.docstatus === 0 && !frm.doc.amended_from) frm.set_value("period_end_date", frappe.datetime.now_datetime());
|
||||
|
||||
|
||||
frappe.realtime.on('closing_process_complete', async function(data) {
|
||||
await frm.reload_doc();
|
||||
if (frm.doc.status == 'Failed' && frm.doc.error_message && data.user == frappe.session.user) {
|
||||
@@ -43,7 +43,7 @@ frappe.ui.form.on('POS Closing Entry', {
|
||||
const issue = '<a id="jump_to_error" style="text-decoration: underline;">issue</a>';
|
||||
frm.dashboard.set_headline(
|
||||
__('POS Closing failed while running in a background process. You can resolve the {0} and retry the process again.', [issue]));
|
||||
|
||||
|
||||
$('#jump_to_error').on('click', (e) => {
|
||||
e.preventDefault();
|
||||
frappe.utils.scroll_to(
|
||||
|
||||
@@ -595,7 +595,8 @@
|
||||
{
|
||||
"fieldname": "scan_barcode",
|
||||
"fieldtype": "Data",
|
||||
"label": "Scan Barcode"
|
||||
"label": "Scan Barcode",
|
||||
"options": "Barcode"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 1,
|
||||
@@ -1553,7 +1554,7 @@
|
||||
"icon": "fa fa-file-text",
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-07-29 13:37:20.636171",
|
||||
"modified": "2021-08-17 20:13:44.255437",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "POS Invoice",
|
||||
|
||||
@@ -5,10 +5,10 @@ frappe.ui.form.on('POS Invoice Merge Log', {
|
||||
setup: function(frm) {
|
||||
frm.set_query("pos_invoice", "pos_invoices", doc => {
|
||||
return{
|
||||
filters: {
|
||||
filters: {
|
||||
'docstatus': 1,
|
||||
'customer': doc.customer,
|
||||
'consolidated_invoice': ''
|
||||
'customer': doc.customer,
|
||||
'consolidated_invoice': ''
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -354,4 +354,4 @@ def safe_load_json(message):
|
||||
except Exception:
|
||||
json_message = message
|
||||
|
||||
return json_message
|
||||
return json_message
|
||||
|
||||
@@ -147,4 +147,3 @@ class TestPOSInvoiceMergeLog(unittest.TestCase):
|
||||
frappe.set_user("Administrator")
|
||||
frappe.db.sql("delete from `tabPOS Profile`")
|
||||
frappe.db.sql("delete from `tabPOS Invoice`")
|
||||
|
||||
|
||||
@@ -53,4 +53,4 @@ frappe.ui.form.on('POS Opening Entry', {
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -38,4 +38,4 @@ class POSOpeningEntry(StatusUpdater):
|
||||
frappe.throw(msg.format(", ".join(invalid_modes)), title=_("Missing Account"))
|
||||
|
||||
def on_submit(self):
|
||||
self.set_status(update=True)
|
||||
self.set_status(update=True)
|
||||
|
||||
@@ -21,8 +21,8 @@ def create_opening_entry(pos_profile, user):
|
||||
balance_details.append(frappe._dict({
|
||||
'mode_of_payment': d.mode_of_payment
|
||||
}))
|
||||
|
||||
|
||||
entry.set("balance_details", balance_details)
|
||||
entry.submit()
|
||||
|
||||
return entry.as_dict()
|
||||
|
||||
return entry.as_dict()
|
||||
|
||||
@@ -8,4 +8,4 @@ from frappe.model.document import Document
|
||||
|
||||
class POSSettings(Document):
|
||||
def validate(self):
|
||||
pass
|
||||
pass
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:title",
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2014-02-21 15:02:51",
|
||||
"doctype": "DocType",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"applicability_section",
|
||||
"naming_series",
|
||||
"title",
|
||||
"disable",
|
||||
"apply_on",
|
||||
@@ -95,8 +96,7 @@
|
||||
"fieldtype": "Data",
|
||||
"label": "Title",
|
||||
"no_copy": 1,
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
@@ -571,6 +571,13 @@
|
||||
"fieldname": "is_recursive",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Recursive"
|
||||
},
|
||||
{
|
||||
"default": "PRLE-.####",
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"label": "Naming Series",
|
||||
"options": "PRLE-.####"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-gift",
|
||||
@@ -634,5 +641,6 @@
|
||||
],
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
||||
"sort_order": "DESC",
|
||||
"title_field": "title"
|
||||
}
|
||||
|
||||
@@ -615,4 +615,4 @@ def delete_existing_pricing_rules():
|
||||
for doctype in ["Pricing Rule", "Pricing Rule Item Code",
|
||||
"Pricing Rule Item Group", "Pricing Rule Brand"]:
|
||||
|
||||
frappe.db.sql("delete from `tab{0}`".format(doctype))
|
||||
frappe.db.sql("delete from `tab{0}`".format(doctype))
|
||||
|
||||
@@ -26,4 +26,3 @@ QUnit.test("test pricing rule", function(assert) {
|
||||
() => done()
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
@@ -31,4 +31,4 @@ class ProcessDeferredAccounting(Document):
|
||||
'against_voucher': self.name
|
||||
})
|
||||
|
||||
make_reverse_gl_entries(gl_entries=gl_entries)
|
||||
make_reverse_gl_entries(gl_entries=gl_entries)
|
||||
|
||||
@@ -45,4 +45,4 @@ class TestProcessDeferredAccounting(unittest.TestCase):
|
||||
["Sales - _TC", 0.0, 33.85, "2019-01-31"]
|
||||
]
|
||||
|
||||
check_gl_entries(self, si.name, expected_gle, "2019-01-10")
|
||||
check_gl_entries(self, si.name, expected_gle, "2019-01-10")
|
||||
|
||||
@@ -284,4 +284,4 @@ def send_auto_email():
|
||||
selected = frappe.get_list('Process Statement Of Accounts', filters={'to_date': format_date(today()), 'enable_auto_email': 1})
|
||||
for entry in selected:
|
||||
send_emails(entry.name, from_scheduler=True)
|
||||
return True
|
||||
return True
|
||||
|
||||
@@ -48,4 +48,4 @@ frappe.ui.form.on('Promotional Scheme', {
|
||||
frm.doc.apply_on === key ? 1 : 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user